Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/overlays/OrxonoxOverlay.cc @ 6676

Last change on this file since 6676 was 6502, checked in by rgrieder, 15 years ago

Removed a ton of msvc warnings revealed with OGRE v1.7 (they removed the warning suppressors in OgrePrerequisites.h).
All of them are conversions from one type to another that might be lossy (mostly double to float, please always use "3.7f" instead of "3.7" as constants when using floats).

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