Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/hudimprovements/src/orxonox/overlays/OrxonoxOverlay.cc @ 8788

Last change on this file since 8788 was 7932, checked in by bknecht, 13 years ago

The boost bar is now flashing red when the boost is cooling down. However the solution in OrxonoxOverlay is a bit questionable and could probably be solved less hacky…

  • Property svn:eol-style set to native
File size: 14.9 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#include <OgreMaterialManager.h>
42#include <OgreTechnique.h>
43#include <OgrePass.h>
44
45#include "util/Convert.h"
46#include "util/Exception.h"
47#include "core/GameMode.h"
48#include "core/CoreIncludes.h"
49#include "core/XMLPort.h"
50#include "core/command/ConsoleCommand.h"
51
52#include "OverlayGroup.h"
53
54namespace orxonox
55{
56    unsigned int OrxonoxOverlay::hudOverlayCounter_s = 0;
57    std::map<std::string, OrxonoxOverlay*> OrxonoxOverlay::overlays_s;
58
59    SetConsoleCommand("OrxonoxOverlay", "scaleOverlay",     &OrxonoxOverlay::scaleOverlay);
60    SetConsoleCommand("OrxonoxOverlay", "scrollOverlay",    &OrxonoxOverlay::scrollOverlay);
61    SetConsoleCommand("OrxonoxOverlay", "toggleVisibility", &OrxonoxOverlay::toggleVisibility);
62    SetConsoleCommand("OrxonoxOverlay", "rotateOverlay",    &OrxonoxOverlay::rotateOverlay);
63
64    OrxonoxOverlay::OrxonoxOverlay(BaseObject* creator)
65        : BaseObject(creator)
66    {
67        RegisterObject(OrxonoxOverlay);
68
69        this->owner_ = 0;
70        this->group_ = 0;
71
72        if (!GameMode::showsGraphics())
73            ThrowException(NoGraphics, "Can't create OrxonoxOverlay, graphics engine not initialized");
74
75        // create the Ogre::Overlay
76        overlay_ = Ogre::OverlayManager::getSingleton().create("OrxonoxOverlay_overlay_"
77            + multi_cast<std::string>(hudOverlayCounter_s++));
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",
82            "OrxonoxOverlay_background_" + multi_cast<std::string>(hudOverlayCounter_s++)));
83        this->overlay_->add2D(this->background_);
84
85        // Get aspect ratio from the render window. Later on, we get informed automatically
86        this->windowAspectRatio_ = static_cast<float>(this->getWindowWidth()) / this->getWindowHeight();
87
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
95
96        setBackgroundMaterial("");
97    }
98
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    */
105    OrxonoxOverlay::~OrxonoxOverlay()
106    {
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);
113
114            Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->background_);
115            Ogre::OverlayManager::getSingleton().destroy(this->overlay_);
116        }
117    }
118
119    /**
120    @brief
121        Loads the OrxonoxOverlay.
122
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    */
128    void OrxonoxOverlay::XMLPort(Element& xmlelement, XMLPort::Mode mode)
129    {
130        SUPER(OrxonoxOverlay, XMLPort, xmlelement, mode);
131
132        XMLPortParam(OrxonoxOverlay, "size",      setSize,      getSize,      xmlelement, mode);
133        XMLPortParam(OrxonoxOverlay, "pickpoint", setPickPoint, getPickPoint, xmlelement, mode);
134        XMLPortParam(OrxonoxOverlay, "position",  setPosition,  getPosition,  xmlelement, mode);
135        XMLPortParam(OrxonoxOverlay, "rotation",  setRotation,  getRotation,  xmlelement, mode);
136        XMLPortParam(OrxonoxOverlay, "correctaspect", setAspectCorrection,   getAspectCorrection,   xmlelement, mode);
137        XMLPortParam(OrxonoxOverlay, "background",    setBackgroundMaterial, getBackgroundMaterial, xmlelement, mode);
138        XMLPortParam(OrxonoxOverlay, "backgroundtex", setBackgroundTexture,  getBackgroundTexture,  xmlelement, mode);
139    }
140
141    void OrxonoxOverlay::changedName()
142    {
143        SUPER(OrxonoxOverlay, changedName);
144
145        OrxonoxOverlay::overlays_s.erase(this->getOldName());
146
147        if (OrxonoxOverlay::overlays_s.find(this->getName()) != OrxonoxOverlay::overlays_s.end())
148            COUT(1) << "Overlay names should be unique or you cannnot access them via console. Name: \"" << this->getName() << '"' << std::endl;
149
150        OrxonoxOverlay::overlays_s[this->getName()] = this;
151    }
152
153    //! Only sets the background material name if not ""
154    void OrxonoxOverlay::setBackgroundMaterial(const std::string& material)
155    {
156        if (this->background_ && !material.empty())
157            this->background_->setMaterialName(material);
158    }
159
160    //! Returns the the material name of the background
161    const std::string& OrxonoxOverlay::getBackgroundMaterial() const
162    {
163        if (this->background_)
164            return this->background_->getMaterialName();
165        else
166            return BLANKSTRING;
167    }
168
169    //! Sets the background texture name and creates a new material if necessary
170    void OrxonoxOverlay::setBackgroundTexture(const std::string& texture)
171    {
172        if (this->background_ && this->background_->getMaterial().isNull() && !texture.empty())
173        {
174            // create new material
175            const std::string& materialname = "generated_material" + getUniqueNumberString();
176            Ogre::MaterialPtr material = static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().create(materialname, "General"));
177            material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
178            Ogre::TextureUnitState* textureUnitState_ = material->getTechnique(0)->getPass(0)->createTextureUnitState();
179            textureUnitState_->setTextureName(texture);
180            textureUnitState_->setNumMipmaps(0);
181            this->background_->setMaterialName(materialname);
182        }
183    }
184
185    //! Returns the the texture name of the background
186    const std::string& OrxonoxOverlay::getBackgroundTexture() const
187    {
188        if (this->background_)
189        {
190            Ogre::TextureUnitState* tempTx = this->background_->getMaterial()->getTechnique(0)->getPass(0)->getTextureUnitState(0);
191            return tempTx->getTextureName();
192        }
193        else
194            return BLANKSTRING;
195    }
196
197    //! Called by BaseObject when visibility has changed.
198    void OrxonoxOverlay::changedVisibility()
199    {
200        SUPER( OrxonoxOverlay, changedVisibility );
201
202        if (!this->overlay_)
203            return;
204
205        // only set to visible if corresponding OverlayGroup is also visible
206        if (this->isVisible() && (!this->getOverlayGroup() || this->getOverlayGroup()->isVisible()) )
207            this->overlay_->show();
208        else
209            this->overlay_->hide();
210    }
211
212    /**
213    @brief
214        Called by the GraphicsManager whenever the window size changes.
215        Calculates the aspect ratio only.
216    */
217    void OrxonoxOverlay::windowResized(unsigned int newWidth, unsigned int newHeight)
218    {
219        this->windowAspectRatio_ = static_cast<float>(newWidth) / newHeight;
220        this->sizeCorrectionChanged();
221    }
222
223    /**
224    @brief
225        Called whenever the rotation angle has changed.
226    */
227    void OrxonoxOverlay::angleChanged()
228    {
229        if (!this->overlay_)
230            return;
231
232        this->overlay_->setRotate(this->angle_);
233        this->sizeCorrectionChanged();
234    }
235
236    /**
237    @brief
238        Called whenever the aspect ratio or the angle has changed.
239        The method calculates a correction factor for the size to compensate
240        for aspect distortion if desired.
241    @remarks
242        This only works when the angle is about 0 or 90 degrees.
243    */
244    void OrxonoxOverlay::sizeCorrectionChanged()
245    {
246        if (this->bCorrectAspect_)
247        {
248            float angle = this->angle_.valueDegrees();
249            if (angle < 0.0)
250                angle = -angle;
251            angle -= 180.0f * static_cast<int>(angle / 180.0);
252
253            // take the reverse if angle is about 90 degrees
254            float tempAspect;
255            if (angle > 89.0f && angle < 91.0f)
256            {
257                tempAspect = 1.0f / this->windowAspectRatio_;
258                rotState_ = Vertical;
259            }
260            else if (angle > 179 || angle < 1)
261            {
262                tempAspect = this->windowAspectRatio_;
263                rotState_ = Horizontal;
264            }
265            else
266            {
267                tempAspect = 1.0f;
268                rotState_ = Inbetween;
269            }
270
271            // note: this is only an approximation that is mostly valid when the
272            // magnitude of the width is about the magnitude of the height.
273            // Correctly we would have to take the square root of width*height
274            this->sizeCorrection_.x = 2.0f / (tempAspect + 1.0f);
275            this->sizeCorrection_.y = tempAspect * this->sizeCorrection_.x;
276        }
277        else
278        {
279            this->sizeCorrection_ = Vector2::UNIT_SCALE;
280        }
281
282        this->sizeChanged();
283    }
284
285    /**
286    @brief
287        Sets the overlay size using the actual corrected size.
288    */
289    void OrxonoxOverlay::sizeChanged()
290    {
291        if (!this->overlay_)
292            return;
293
294        this->overlay_->setScale(size_.x * sizeCorrection_.x, size_.y * sizeCorrection_.y);
295        positionChanged();
296    }
297
298    /**
299    @brief
300        Determines the position of the overlay.
301        This works also well when a rotation angle is applied. The overlay always
302        gets aligned correctly as well as possible.
303    */
304    void OrxonoxOverlay::positionChanged()
305    {
306        if (!this->overlay_)
307            return;
308
309        // transform the angle to a range of 0 - pi/2 first.
310        float angle = this->angle_.valueRadians();
311        if (angle < 0.0)
312            angle = -angle;
313        angle -= math::pi * static_cast<int>(angle / (math::pi));
314        if (angle > math::pi * 0.5)
315            angle = math::pi - angle;
316
317        // do some mathematical fiddling for a bounding box
318        Vector2 actualSize = size_ * sizeCorrection_;
319        float radius = actualSize.length();
320        float phi = atan(actualSize.y / actualSize.x);
321        Vector2 boundingBox(radius * cos(angle - phi), radius * sin(angle + phi));
322
323        // calculate the scrolling offset
324        Vector2 scroll = (position_ - 0.5 - boundingBox * (pickPoint_ - 0.5)) * 2.0;
325        this->overlay_->setScroll(scroll.x, -scroll.y);
326    }
327
328
329    //########### Console commands ############
330
331    /**
332    @brief
333        Scales an overlay by its name.
334    @param name
335        The name of the overlay defined BaseObject::setName() (usually done with the "name"
336        attribute in the xml file).
337    @param scale
338        The scaling factor
339    */
340    /*static*/ void OrxonoxOverlay::scaleOverlay(const std::string& name, float scale)
341    {
342        std::map<std::string, OrxonoxOverlay*>::const_iterator it = overlays_s.find(name);
343        if (it != overlays_s.end())
344            it->second->scale(Vector2(scale, scale));
345    }
346
347    /**
348    @brief
349        Toggles the visibility of an Overlay by it's name.
350    @param name
351        The name of the overlay defined BaseObject::setName() (usually done with the "name"
352        attribute in the xml file).
353    */
354    /*static*/ void OrxonoxOverlay::toggleVisibility(const std::string& name)
355    {
356        std::map<std::string, OrxonoxOverlay*>::const_iterator it = overlays_s.find(name);
357        if (it != overlays_s.end())
358        {
359            OrxonoxOverlay* overlay= it->second;
360            if(overlay->isVisible())
361            {
362                overlay->hide();
363                COUT(4) << "HIDE " << name << std::endl;
364            }
365            else
366            {
367                overlay->show();
368                COUT(4) << "SHOW " << name << std::endl;
369            }
370        }
371    }
372
373    /**
374    @brief
375        Scrolls an overlay by its name.
376    @param name
377        The name of the overlay defined BaseObject::setName() (usually done with the "name"
378        attribute in the xml file).
379    @param scroll
380        The relative translation of the overlay
381    */
382    /*static*/ void OrxonoxOverlay::scrollOverlay(const std::string& name, const Vector2& scroll)
383    {
384        std::map<std::string, OrxonoxOverlay*>::const_iterator it = overlays_s.find(name);
385        if (it != overlays_s.end())
386            it->second->scroll(scroll);
387    }
388
389    /**
390    @brief
391        Rotates an overlay by its name.
392    @param name
393        The name of the overlay defined BaseObject::setName() (usually done with the "name"
394        attribute in the xml file).
395    @param angle
396        The rotation angle in degree
397    */
398    /*static*/ void OrxonoxOverlay::rotateOverlay(const std::string& name, const Degree& angle)
399    {
400        std::map<std::string, OrxonoxOverlay*>::const_iterator it = overlays_s.find(name);
401        if (it != overlays_s.end())
402            it->second->rotate(angle);
403    }
404
405    void OrxonoxOverlay::setOverlayGroup(OverlayGroup* group)
406    {
407        if (group != this->group_)
408        {
409            if (this->group_)
410                this->group_->removeElement(this);
411            this->group_ = group;
412            this->changedOverlayGroup();
413        }
414    }
415
416    void OrxonoxOverlay::setBackgroundAlpha(float alpha)
417    {
418        Ogre::MaterialPtr ptr = this->background_->getMaterial();
419        Ogre::TextureUnitState* tempTx = ptr->getTechnique(0)->getPass(0)->getTextureUnitState(0);
420        tempTx->setAlphaOperation(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, alpha);
421    }
422
423    void OrxonoxOverlay::setBackgroundColour(ColourValue colour)
424    {
425        Ogre::MaterialPtr ptr = this->background_->getMaterial();
426        Ogre::TextureUnitState* tempTx = ptr->getTechnique(0)->getPass(0)->getTextureUnitState(0);
427        tempTx->setColourOperationEx(Ogre::LBX_MODULATE, Ogre::LBS_MANUAL, Ogre::LBS_CURRENT, colour);
428    }
429}
Note: See TracBrowser for help on using the repository browser.