Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8749 was 8706, checked in by dafrick, 13 years ago

Merging presentation branch back into trunk.
There are many new features and also a lot of other changes and bugfixes, if you want to know, digg through the svn log.
Not everything is yet working as it should, but it should be fairly stable. If you habe any bug reports, just send me an email.

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