Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 2801 was 2801, checked in by rgrieder, 15 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
RevLine 
[1588]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
[1622]29/**
30@file
31@brief Definition of the OrxonoxOverlay class.
32*/
33
[1588]34#include "OrxonoxStableHeaders.h"
[1601]35#include "OrxonoxOverlay.h"
[1588]36
[1615]37#include <cmath>
[1622]38#include <OgreOverlay.h>
[1588]39#include <OgreOverlayManager.h>
[1614]40#include <OgrePanelOverlayElement.h>
[2801]41#include <OgreRenderWindow.h>
42
[1588]43#include "util/Convert.h"
[2171]44#include "util/Exception.h"
[1615]45#include "util/String.h"
[2171]46#include "core/Core.h"
[1588]47#include "core/CoreIncludes.h"
[1616]48#include "core/XMLPort.h"
49#include "core/ConsoleCommand.h"
[2801]50#include "GraphicsManager.h"
[1588]51
52namespace orxonox
53{
[1615]54    unsigned int OrxonoxOverlay::hudOverlayCounter_s = 0;
55    std::map<std::string, OrxonoxOverlay*> OrxonoxOverlay::overlays_s;
[1588]56
[1747]57    SetConsoleCommand(OrxonoxOverlay, scaleOverlay, false).accessLevel(AccessLevel::User);
58    SetConsoleCommand(OrxonoxOverlay, scrollOverlay, false).accessLevel(AccessLevel::User);
59    SetConsoleCommand(OrxonoxOverlay, rotateOverlay, false).accessLevel(AccessLevel::User);
[1588]60
[2087]61    OrxonoxOverlay::OrxonoxOverlay(BaseObject* creator)
62        : BaseObject(creator)
[1615]63    {
64        RegisterObject(OrxonoxOverlay);
[2087]65
[2662]66        this->owner_ = 0;
67        this->group_ = 0;
68
[2171]69        if (!Core::showsGraphics())
70            ThrowException(NoGraphics, "Can't create OrxonoxOverlay, graphics engine not initialized");
71
[2087]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
[2801]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();
[2087]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));
[2662]93        setAspectCorrection(false);
[2087]94        setBackgroundMaterial("");
[1615]95    }
[1614]96
[1622]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    */
[1615]103    OrxonoxOverlay::~OrxonoxOverlay()
104    {
[2087]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);
[1622]111
112            Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->background_);
113            Ogre::OverlayManager::getSingleton().destroy(this->overlay_);
[2087]114        }
[1615]115    }
116
[1622]117    /**
118    @brief
119        Loads the OrxonoxOverlay.
[1747]120
[1622]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    */
[1615]126    void OrxonoxOverlay::XMLPort(Element& xmlElement, XMLPort::Mode mode)
[1590]127    {
[1747]128        SUPER(OrxonoxOverlay, XMLPort, xmlElement, mode);
[1588]129
[2087]130        XMLPortParam(OrxonoxOverlay, "size",      setSize,      getSize,      xmlElement, mode);
[2662]131        XMLPortParam(OrxonoxOverlay, "pickpoint", setPickPoint, getPickPoint, xmlElement, mode);
[2087]132        XMLPortParam(OrxonoxOverlay, "position",  setPosition,  getPosition,  xmlElement, mode);
133        XMLPortParam(OrxonoxOverlay, "rotation",  setRotation,  getRotation,  xmlElement, mode);
[2662]134        XMLPortParam(OrxonoxOverlay, "correctaspect", setAspectCorrection,   getAspectCorrection,   xmlElement, mode);
[2087]135        XMLPortParam(OrxonoxOverlay, "background",    setBackgroundMaterial, getBackgroundMaterial, xmlElement, mode);
136    }
[1614]137
[2087]138    void OrxonoxOverlay::changedName()
139    {
[2662]140        SUPER(OrxonoxOverlay, changedName);
141
[2087]142        OrxonoxOverlay::overlays_s.erase(this->getOldName());
[1590]143
[2087]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;
[1588]146
[2087]147        OrxonoxOverlay::overlays_s[this->getName()] = this;
[1590]148    }
[1588]149
[1622]150    //! Only sets the background material name if not ""
[1615]151    void OrxonoxOverlay::setBackgroundMaterial(const std::string& material)
152    {
153        if (this->background_ && material != "")
154            this->background_->setMaterialName(material);
155    }
[1588]156
[1622]157    //! Returns the the material name of the background
[1615]158    const std::string& OrxonoxOverlay::getBackgroundMaterial() const
159    {
160        if (this->background_)
161            return this->background_->getMaterialName();
162        else
[2087]163            return BLANKSTRING;
[1615]164    }
[1614]165
[1622]166    //! Called by BaseObject when visibility has changed.
[1615]167    void OrxonoxOverlay::changedVisibility()
[1595]168    {
[1622]169        if (!this->overlay_)
170            return;
171
172        if (this->isVisible())
173            this->overlay_->show();
174        else
175            this->overlay_->hide();
[1595]176    }
[1588]177
[1622]178    /**
179    @brief
[2801]180        Called by the GraphicsManager whenever the window size changes.
[1622]181        Calculates the aspect ratio only.
182    */
[2801]183    void OrxonoxOverlay::windowResized(unsigned int newWidth, unsigned int newHeight)
[1615]184    {
185        this->windowAspectRatio_ = newWidth/(float)newHeight;
[1622]186        this->sizeCorrectionChanged();
[1615]187    }
[1590]188
[1622]189    /**
190    @brief
191        Called whenever the rotation angle has changed.
192    */
193    void OrxonoxOverlay::angleChanged()
[1595]194    {
[1622]195        if (!this->overlay_)
196            return;
197
198        this->overlay_->setRotate(this->angle_);
[1615]199        this->sizeCorrectionChanged();
[1595]200    }
[1615]201
[1622]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    */
[1615]210    void OrxonoxOverlay::sizeCorrectionChanged()
[1595]211    {
[1615]212        if (this->bCorrectAspect_)
213        {
214            float angle = this->angle_.valueDegrees();
[1618]215            if (angle < 0.0)
216                angle = -angle;
217            angle -= 180.0 * (int)(angle / 180.0);
218
[1622]219            // take the reverse if angle is about 90 degrees
[1615]220            float tempAspect;
[1618]221            if (angle > 89.0 && angle < 91.0)
[1632]222            {
[1615]223                tempAspect = 1.0 / this->windowAspectRatio_;
[1632]224                rotState_ = Vertical;
225            }
[1618]226            else if (angle > 179 || angle < 1)
[1632]227            {
[1615]228                tempAspect = this->windowAspectRatio_;
[1632]229                rotState_ = Horizontal;
230            }
[1615]231            else
[1632]232            {
[1615]233                tempAspect = 1.0;
[1632]234                rotState_ = Inbetween;
235            }
[1615]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        }
[1622]247
[1615]248        this->sizeChanged();
[1595]249    }
250
[1615]251    /**
[1622]252    @brief
253        Sets the overlay size using the actual corrected size.
[1615]254    */
255    void OrxonoxOverlay::sizeChanged()
256    {
[1622]257        if (!this->overlay_)
258            return;
259
[1615]260        this->overlay_->setScale(size_.x * sizeCorrection_.x, size_.y * sizeCorrection_.y);
261        positionChanged();
262    }
[1595]263
[1615]264    /**
[1622]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.
[1615]269    */
[1622]270    void OrxonoxOverlay::positionChanged()
[1615]271    {
[1622]272        if (!this->overlay_)
273            return;
[1595]274
[1622]275        // transform the angle to a range of 0 - pi/2 first.
[1617]276        float angle = this->angle_.valueRadians();
277        if (angle < 0.0)
278            angle = -angle;
[1615]279        angle -= Ogre::Math::PI * (int)(angle / (Ogre::Math::PI));
280        if (angle > Ogre::Math::PI * 0.5)
281            angle = Ogre::Math::PI - angle;
[1747]282
[1622]283        // do some mathematical fiddling for a bounding box
[1615]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));
[1622]288
289        // calculate the scrolling offset
290        Vector2 scroll = (position_ - 0.5 - boundingBox * (pickPoint_ - 0.5)) * 2.0;
[1615]291        this->overlay_->setScroll(scroll.x, -scroll.y);
292    }
[1598]293
[1615]294
[1622]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"
[1623]302        attribute in the xml file).
[1622]303    */
[1615]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
[1622]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"
[1623]316        attribute in the xml file).
[1622]317    */
[1615]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
[1622]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"
[1623]330        attribute in the xml file).
[1622]331    */
[1615]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    }
[1588]338}
Note: See TracBrowser for help on using the repository browser.