Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/spaceNavigation/src/modules/overlays/hud/HUDNavigation.cc @ 9434

Last change on this file since 9434 was 9434, checked in by mottetb, 11 years ago

aimMarkerSize aendert nichts im Spiel

  • Property svn:eol-style set to native
File size: 21.4 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 *      Felix Schulthess
24 *   Co-authors:
25 *      Reto Grieder
26 *      Oliver Scheuss
27 *      Matthias Spalinger
28 *
29 */
30
31#include "HUDNavigation.h"
32
33#include <OgreCamera.h>
34#include <OgreFontManager.h>
35#include <OgreOverlayManager.h>
36#include <OgreTextAreaOverlayElement.h>
37#include <OgrePanelOverlayElement.h>
38
39#include "util/Math.h"
40#include "util/Convert.h"
41#include "core/CoreIncludes.h"
42#include "core/XMLPort.h"
43#include "CameraManager.h"
44#include "Scene.h"
45#include "Radar.h"
46#include "graphics/Camera.h"
47#include "controllers/HumanController.h"
48#include "worldentities/pawns/Pawn.h"
49#include "worldentities/WorldEntity.h"
50#include "core/ConfigValueIncludes.h"
51#include "tools/TextureGenerator.h"
52// #include <boost/bind/bind_template.hpp>
53
54
55namespace orxonox
56{
57    static bool compareDistance(std::pair<RadarViewable*, unsigned int> a,
58            std::pair<RadarViewable*, unsigned int> b)
59    {
60        return a.second < b.second;
61    }
62    CreateFactory ( HUDNavigation );
63
64    HUDNavigation::HUDNavigation(BaseObject* creator) :
65        OrxonoxOverlay(creator)
66    {
67        RegisterObject(HUDNavigation)
68;        this->setConfigValues();
69
70        // Set default values
71        this->setFont("Monofur");
72        this->setTextSize(0.05f);
73        this->setNavMarkerSize(0.05f);
74        this->setAimMarkerSize(0.02f);
75
76        this->setDetectionLimit(10000.0f);
77        this->currentMunitionSpeed_ = 2500.0f;
78
79        /*Pawn* ship = orxonox_cast<Pawn*>(this->getOwner());
80        if(ship != NULL)
81            this->ship_ = ship;*/
82    }
83
84    HUDNavigation::~HUDNavigation()
85    {
86        if (this->isInitialized())
87        {
88            for (std::map<RadarViewable*, ObjectInfo>::iterator it = this->activeObjectList_.begin(); it != this->activeObjectList_.end();)
89            removeObject((it++)->first);
90        }
91        this->sortedObjectList_.clear();
92    }
93
94    void HUDNavigation::setConfigValues()
95    {
96        SetConfigValue(markerLimit_, 3);
97        SetConfigValue(showDistance_, false);
98    }
99
100    void HUDNavigation::XMLPort(Element& xmlelement, XMLPort::Mode mode)
101    {
102        SUPER(HUDNavigation, XMLPort, xmlelement, mode);
103
104        XMLPortParam(HUDNavigation, "font", setFont, getFont, xmlelement, mode);
105        XMLPortParam(HUDNavigation, "textSize", setTextSize, getTextSize, xmlelement, mode);
106        XMLPortParam(HUDNavigation, "navMarkerSize", setNavMarkerSize, getNavMarkerSize, xmlelement, mode);
107        XMLPortParam(HUDNavigation, "detectionLimit", setDetectionLimit, getDetectionLimit, xmlelement, mode);
108        XMLPortParam(HUDNavigation, "aimMarkerSize", setAimMarkerSize, getAimMarkerSize, xmlelement, mode);
109    }
110
111    void HUDNavigation::setFont(const std::string& font)
112    {
113        const Ogre::ResourcePtr& fontPtr = Ogre::FontManager::getSingleton().getByName(font);
114        if (fontPtr.isNull())
115        {
116            orxout(internal_warning) << "HUDNavigation: Font '" << font << "' not found" << endl;
117            return;
118        }
119        this->fontName_ = font;
120        for (std::map<RadarViewable*, ObjectInfo>::iterator it = this->activeObjectList_.begin(); it != this->activeObjectList_.end(); ++it)
121        {
122            if (it->second.text_ != NULL)
123            it->second.text_->setFontName(this->fontName_);
124        }
125    }
126
127    const std::string& HUDNavigation::getFont() const
128    {
129        return this->fontName_;
130    }
131
132    void HUDNavigation::setTextSize(float size)
133    {
134        if (size <= 0.0f)
135        {
136            orxout(internal_warning) << "HUDNavigation: Negative font size not allowed" << endl;
137            return;
138        }
139        this->textSize_ = size;
140        for (std::map<RadarViewable*, ObjectInfo>::iterator it = this->activeObjectList_.begin(); it!=this->activeObjectList_.end(); ++it)
141        {
142            if (it->second.text_)
143            it->second.text_->setCharHeight(size);
144        }
145    }
146
147    float HUDNavigation::getTextSize() const
148    {
149        return this->textSize_;
150    }
151
152    float HUDNavigation::getArrowSizeX(int dist) const
153    {
154        if (dist < 600)
155        dist = 600;
156        return this->getActualSize().x * 900 * this->navMarkerSize_ / dist;
157    }
158
159    float HUDNavigation::getArrowSizeY(int dist) const
160    {
161        if (dist < 600)
162        dist = 600;
163        return this->getActualSize().y * 900 * this->navMarkerSize_ / dist;
164    }
165
166    void HUDNavigation::tick(float dt)
167    {
168        SUPER(HUDNavigation, tick, dt);
169
170        Camera* cam = CameraManager::getInstance().getActiveCamera();
171        if (cam == NULL)
172        return;
173        const Matrix4& camTransform = cam->getOgreCamera()->getProjectionMatrix() * cam->getOgreCamera()->getViewMatrix();
174
175        for (std::list<std::pair<RadarViewable*, unsigned int> >::iterator listIt = this->sortedObjectList_.begin(); listIt != this->sortedObjectList_.end(); ++listIt)
176        listIt->second = (int)((listIt->first->getRVWorldPosition() - HumanController::getLocalControllerSingleton()->getControllableEntity()->getWorldPosition()).length() + 0.5f);
177
178        this->sortedObjectList_.sort(compareDistance);
179
180        unsigned int markerCount = 0;
181        bool closeEnough = false; // only display objects that are close enough to be relevant for the player
182
183        for (std::list<std::pair<RadarViewable*, unsigned int> >::iterator listIt = this->sortedObjectList_.begin(); listIt != this->sortedObjectList_.end(); ++markerCount, ++listIt)
184        {
185            std::map<RadarViewable*, ObjectInfo>::iterator it = this->activeObjectList_.find(listIt->first);
186            closeEnough = listIt->second < this->detectionLimit_;
187            // display radarviewables on HUD if the marker limit and max-distance is not exceeded
188            if (markerCount < this->markerLimit_ && (closeEnough || this->detectionLimit_ < 0))
189            {
190                // Get Distance to HumanController and save it in the TextAreaOverlayElement.
191                int dist = listIt->second;
192                float textLength = 0.0f;
193
194                if (this->showDistance_)
195                {
196                    //display distance next to cursor
197                    it->second.text_->setCaption(multi_cast<std::string>(dist));
198                    textLength = multi_cast<std::string>(dist).size() * it->second.text_->getCharHeight() * 0.3f;
199                }
200                else
201                {
202                    //display name next to cursor
203                    it->second.text_->setCaption(it->first->getRadarName());
204                    textLength = it->first->getRadarName().size() * it->second.text_->getCharHeight() * 0.3f;
205                }
206
207                // TODO : closest object is selected
208                if(listIt == this->sortedObjectList_.begin())
209                {
210                    it->second.selected_ = true;
211                } else {
212                    it->second.selected_ = false;
213                }
214
215                // Transform to screen coordinates
216                Vector3 pos = camTransform * it->first->getRVWorldPosition();
217
218                bool outOfView = true;
219                if (pos.z > 1.0)
220                {
221                    // z > 1.0 means that the object is behind the camera
222                    outOfView = true;
223                    // we have to switch all coordinates (if you don't know why,
224                    // try linear algebra lectures, because I can't explain..)
225                    pos.x = -pos.x;
226                    pos.y = -pos.y;
227                }
228                else
229                outOfView = pos.x < -1.0 || pos.x > 1.0 || pos.y < -1.0 || pos.y > 1.0;
230
231                if (outOfView)
232                {
233                    // Object is not in view
234
235                    // Change material only if outOfView changed
236                    if (!it->second.wasOutOfView_)
237                    {
238                        it->second.panel_->setMaterialName(TextureGenerator::getMaterialName("arrows.png", it->first->getRadarObjectColour()));
239                        it->second.wasOutOfView_ = true;
240                        it->second.target_->hide();
241                    }
242
243                    //float xDistScale = this->getActualSize().x * 1000.0f * this->navMarkerSize_ / dist;
244                    //float yDistScale = this->getActualSize().y * 1000.0f * this->navMarkerSize_ / dist;
245
246                    // Adjust Arrowsize according to distance
247                    it->second.panel_->setDimensions(getArrowSizeX(dist), getArrowSizeY(dist));
248
249                    // Switch between top, bottom, left and right position of the arrow at the screen border
250                    if (pos.x < pos.y)
251                    {
252                        if (pos.y > -pos.x)
253                        {
254                            // Top
255                            float position = pos.x / pos.y + 1.0f;
256                            it->second.panel_->setPosition((position - it->second.panel_->getWidth()) * 0.5f, 0.0f);
257                            it->second.panel_->setUV(0.5f, 0.0f, 1.0f, 0.5f);
258                            it->second.text_->setLeft((position - textLength) * 0.5f);
259                            it->second.text_->setTop(it->second.panel_->getHeight());
260                        }
261                        else
262                        {
263                            // Left
264                            float position = pos.y / pos.x + 1.0f;
265                            it->second.panel_->setPosition(0.0f, (position - it->second.panel_->getWidth()) * 0.5f);
266                            it->second.panel_->setUV(0.0f, 0.0f, 0.5f, 0.5f);
267                            it->second.text_->setLeft(it->second.panel_->getWidth() + 0.01f);
268                            it->second.text_->setTop((position - it->second.text_->getCharHeight()) * 0.5f);
269                        }
270                    }
271                    else
272                    {
273                        if (pos.y < -pos.x)
274                        {
275                            // Bottom
276                            float position = -pos.x / pos.y + 1.0f;
277                            it->second.panel_->setPosition((position - it->second.panel_->getWidth()) * 0.5f, 1.0f - it->second.panel_->getHeight());
278                            it->second.panel_->setUV(0.0f, 0.5f, 0.5f, 1.0f );
279                            it->second.text_->setLeft((position - textLength) * 0.5f);
280                            it->second.text_->setTop(1.0f - it->second.panel_->getHeight() - it->second.text_->getCharHeight());
281                        }
282                        else
283                        {
284                            // Right
285                            float position = -pos.y / pos.x + 1.0f;
286                            it->second.panel_->setPosition(1.0f - it->second.panel_->getWidth(), (position - it->second.panel_->getHeight()) * 0.5f);
287                            it->second.panel_->setUV(0.5f, 0.5f, 1.0f, 1.0f);
288                            it->second.text_->setLeft(1.0f - it->second.panel_->getWidth() - textLength - 0.01f);
289                            it->second.text_->setTop((position - it->second.text_->getCharHeight()) * 0.5f);
290                        }
291                    }
292                }
293                else
294                {
295                    // Object is in view
296
297                    // Change material only if outOfView changed
298                    if (it->second.wasOutOfView_)
299                    {
300                        //it->second.panel_->setMaterialName("Orxonox/NavTDC");
301                        it->second.panel_->setMaterialName(TextureGenerator::getMaterialName("tdc.png", it->first->getRadarObjectColour()));
302                        it->second.panel_->setDimensions(this->navMarkerSize_ * this->getActualSize().x, this->navMarkerSize_ * this->getActualSize().y);
303                        it->second.target_->setDimensions(this->aimMarkerSize_ * this->getActualSize().x, this->aimMarkerSize_ * this->getActualSize().y);
304                        it->second.wasOutOfView_ = false;
305                    }
306
307                    // Position marker
308                    it->second.panel_->setUV(0.0f, 0.0f, 1.0f, 1.0f);
309                    it->second.panel_->setLeft((pos.x + 1.0f - it->second.panel_->getWidth()) * 0.5f);
310                    it->second.panel_->setTop((-pos.y + 1.0f - it->second.panel_->getHeight()) * 0.5f);
311
312                    // Position text
313                    it->second.text_->setLeft((pos.x + 1.0f + it->second.panel_->getWidth()) * 0.5f);
314                    it->second.text_->setTop((-pos.y + 1.0f + it->second.panel_->getHeight()) * 0.5f);
315
316                    // Target marker
317                    if(it->second.selected_)
318                    {
319                        Vector3* targetPos = this->toAimPosition(it->first);
320                        Vector3 screenPos = camTransform * *targetPos;
321                        // Check if the target marker is in view too
322                        if(screenPos.z > 1 || screenPos.x < -1.0 || screenPos.x > 1.0
323                                || screenPos.y < -1.0 || screenPos.y > 1.0)
324                        {
325                            it->second.target_->hide();
326                        }
327                        else
328                        {
329                            it->second.target_->setLeft((screenPos.x + 1.0f - it->second.target_->getWidth()) * 0.5f);
330                            it->second.target_->setTop((-screenPos.y + 1.0f - it->second.target_->getHeight()) * 0.5f);
331                            it->second.target_->show();
332                        }
333
334                        delete targetPos;
335                    }
336                    else // don't show marker for not selected enemies
337                        it->second.target_->hide();
338                }
339
340                // Make sure the overlays are shown
341                it->second.panel_->show();
342                it->second.text_->show();
343            }
344            else // do not display on HUD
345
346            {
347                it->second.panel_->hide();
348                it->second.text_->hide();
349                it->second.target_->hide();
350            }
351        }
352    }
353
354    /** Overridden method of OrxonoxOverlay.
355     @details
356     Usually the entire overlay scales with scale().
357     Here we obviously have to adjust this.
358     */
359    void HUDNavigation::sizeChanged()
360    {
361        // Use size to compensate for aspect ratio if enabled.
362        float xScale = this->getActualSize().x;
363        float yScale = this->getActualSize().y;
364
365        for (std::map<RadarViewable*, ObjectInfo>::iterator it = this->activeObjectList_.begin(); it != this->activeObjectList_.end(); ++it)
366        {
367            if (it->second.panel_ != NULL)
368                it->second.panel_->setDimensions(this->navMarkerSize_ * xScale, this->navMarkerSize_ * yScale);
369            if (it->second.text_ != NULL)
370                it->second.text_->setCharHeight(it->second.text_->getCharHeight() * yScale);
371            if (it->second.target_ != NULL)
372                it->second.target_->setDimensions(this->aimMarkerSize_ * xScale, this->aimMarkerSize_ * yScale);
373        }
374    }
375
376    void HUDNavigation::addObject(RadarViewable* object)
377    {
378        if (showObject(object) == false)
379        return;
380
381        if (this->activeObjectList_.size() >= this->markerLimit_)
382        if (object == NULL)
383        return;
384
385        // Object hasn't been added yet (we know that)
386        assert(this->activeObjectList_.find(object) == this->activeObjectList_.end());
387
388        // Scales used for dimensions and text size
389        float xScale = this->getActualSize().x;
390        float yScale = this->getActualSize().y;
391
392        // Create everything needed to display the object on the radar and add it to the map
393
394        // Create arrow/marker
395        Ogre::PanelOverlayElement* panel = static_cast<Ogre::PanelOverlayElement*>( Ogre::OverlayManager::getSingleton()
396                .createOverlayElement("Panel", "HUDNavigation_navMarker_" + getUniqueNumberString()));
397        //panel->setMaterialName("Orxonox/NavTDC");
398        panel->setMaterialName(TextureGenerator::getMaterialName("tdc.png", object->getRadarObjectColour()));
399        panel->setDimensions(this->navMarkerSize_ * xScale, this->navMarkerSize_ * yScale);
400        //panel->setColour(object->getRadarObjectColour());
401
402        // Create target marker
403        Ogre::PanelOverlayElement* target = static_cast<Ogre::PanelOverlayElement*>(Ogre::OverlayManager::getSingleton()
404                .createOverlayElement("Panel", "HUDNavigation_targetMarker_" + getUniqueNumberString()));
405        target->setMaterialName(TextureGenerator::getMaterialName("target.png", object->getRadarObjectColour()));
406        target->setDimensions(this->aimMarkerSize_ * xScale, this->aimMarkerSize_ * yScale);
407
408        // Create text
409        Ogre::TextAreaOverlayElement* text = static_cast<Ogre::TextAreaOverlayElement*>( Ogre::OverlayManager::getSingleton()
410                .createOverlayElement("TextArea", "HUDNavigation_navText_" + getUniqueNumberString()));
411        text->setFontName(this->fontName_);
412        text->setCharHeight(text->getCharHeight() * yScale);
413        text->setColour(object->getRadarObjectColour());
414
415        panel->hide();
416        target->hide();
417        text->hide();
418
419        ObjectInfo tempStruct =
420        {   panel, target, text, false, false, false};
421        this->activeObjectList_[object] = tempStruct;
422
423        this->background_->addChild(panel);
424        this->background_->addChild(target);
425        this->background_->addChild(text);
426
427        this->sortedObjectList_.push_front(std::make_pair(object, (unsigned int)0));
428    }
429
430    void HUDNavigation::removeObject(RadarViewable* viewable)
431    {
432        std::map<RadarViewable*, ObjectInfo>::iterator it = this->activeObjectList_.find(viewable);
433
434        if (this->activeObjectList_.find(viewable) != this->activeObjectList_.end())
435        {
436            // Detach overlays
437            this->background_->removeChild(it->second.panel_->getName());
438            this->background_->removeChild(it->second.target_->getName());
439            this->background_->removeChild(it->second.text_->getName());
440            // Properly destroy the overlay elements (do not use delete!)
441            Ogre::OverlayManager::getSingleton().destroyOverlayElement(it->second.panel_);
442            Ogre::OverlayManager::getSingleton().destroyOverlayElement(it->second.target_);
443            Ogre::OverlayManager::getSingleton().destroyOverlayElement(it->second.text_);
444            // Remove from the list
445            this->activeObjectList_.erase(viewable);
446        }
447
448        for (std::list<std::pair<RadarViewable*, unsigned int> >::iterator listIt = this->sortedObjectList_.begin(); listIt != this->sortedObjectList_.end(); ++listIt)
449        {
450            if ((listIt->first) == viewable)
451            {
452                this->sortedObjectList_.erase(listIt);
453                break;
454            }
455        }
456    }
457
458    void HUDNavigation::objectChanged(RadarViewable* viewable)
459    {
460        // TODO: niceification neccessary ;)
461        removeObject(viewable);
462        addObject(viewable);
463    }
464
465    bool HUDNavigation::showObject(RadarViewable* rv)
466    {
467        if (rv == orxonox_cast<RadarViewable*>(this->getOwner()))
468        return false;
469        assert(rv->getWorldEntity());
470        if (rv->getWorldEntity()->isVisible() == false || rv->getRadarVisibility() == false)
471        return false;
472        return true;
473    }
474
475    void HUDNavigation::changedOwner()
476    {
477        const std::set<RadarViewable*>& respawnObjects = this->getOwner()->getScene()->getRadar()->getRadarObjects();
478        for (std::set<RadarViewable*>::const_iterator it = respawnObjects.begin(); it != respawnObjects.end(); ++it)
479        {
480            if (!(*it)->isHumanShip_)
481            this->addObject(*it);
482        }
483    }
484
485    Vector3* HUDNavigation::toAimPosition(RadarViewable* target) const
486    {
487        Vector3 wePosition = HumanController::getLocalControllerSingleton()->getControllableEntity()->getWorldPosition();
488        Vector3 targetPosition = target->getRVWorldPosition();
489        Vector3 targetSpeed = target->getRVOrientedVelocity();
490
491        // munSpeed*time = lengthBetween(wePosition, targetPosition + targetSpeed*time)
492        // from this we extract:
493        float a = pow(targetSpeed.length(),2) - pow(this->currentMunitionSpeed_,2);
494        float b = 2*((targetPosition.x - wePosition.x)*targetSpeed.x
495                    +(targetPosition.y - wePosition.y)*targetSpeed.y
496                    +(targetPosition.z - wePosition.z)*targetSpeed.z);
497        float c = pow((targetPosition-wePosition).length(),2);
498
499        // calculate smallest time solution, in case it exists
500        if(pow(b,2) - 4*a*c < 0)
501            return NULL;
502        float time = (-b - sqrt(pow(b,2) - 4*a*c))/(2*a);
503        if(time < 0)
504            time = (-b + sqrt(pow(b,2) - 4*a*c))/(2*a);
505        if(time < 0)
506            return NULL;
507        Vector3* result = new Vector3(targetPosition + targetSpeed * time);
508        return result;
509    }
510}
Note: See TracBrowser for help on using the repository browser.