Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/orxonox/overlays/console/InGameConsole.cc @ 1641

Last change on this file since 1641 was 1641, checked in by rgrieder, 16 years ago

some de-bugging
added enum for joy stick buttons
some more little fixes

  • Property svn:eol-style set to native
File size: 22.3 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 *      Fabian 'x3n' Landau
26 *
27 */
28
29#include "OrxonoxStableHeaders.h"
30
31#include "InGameConsole.h"
32
33#include <string>
34#include <OgreOverlay.h>
35#include <OgreOverlayElement.h>
36#include <OgreOverlayManager.h>
37#include <OgreOverlayContainer.h>
38#include <OgreFontManager.h>
39#include <OgreFont.h>
40
41#include "util/Math.h"
42#include "util/Convert.h"
43#include "core/Debug.h"
44#include "core/CoreIncludes.h"
45#include "core/ConfigValueIncludes.h"
46#include "core/ConsoleCommand.h"
47#include "core/input/InputManager.h"
48#include "core/input/SimpleInputState.h"
49#include "core/input/InputBuffer.h"
50#include "GraphicsEngine.h"
51
52#define LINES 30
53#define CHAR_WIDTH 7.45 // fix this please - determine the char-width dynamically
54
55namespace orxonox
56{
57    SetConsoleCommand(InGameConsole, openConsole, true);
58    SetConsoleCommand(InGameConsole, closeConsole, true);
59
60    /**
61        @brief Constructor: Creates and initializes the InGameConsole.
62    */
63    InGameConsole::InGameConsole()
64        : consoleOverlay_(0)
65        , consoleOverlayContainer_(0)
66        , consoleOverlayNoise_(0)
67        , consoleOverlayCursor_(0)
68        , consoleOverlayBorder_(0)
69        , consoleOverlayTextAreas_(0)
70    {
71        RegisterObject(InGameConsole);
72
73        this->bActive_ = false;
74        this->cursor_ = 0.0f;
75        this->cursorSymbol_ = '|';
76        this->inputWindowStart_ = 0;
77        this->numLinesShifted_ = LINES - 1;
78        // for the beginning, don't scroll
79        this->scroll_ = 0;
80
81        this->setConfigValues();
82    }
83
84    /**
85        @brief Destructor: Destroys the TextAreas.
86    */
87    InGameConsole::~InGameConsole(void)
88    {
89        this->destroy();
90    }
91
92    /**
93        @brief Returns a reference to the only existing instance of InGameConsole.
94    */
95    InGameConsole& InGameConsole::getInstance()
96    {
97        static InGameConsole instance;
98        return instance;
99    }
100
101    /**
102        @brief Sets the config values, describing the size of the console.
103    */
104    void InGameConsole::setConfigValues()
105    {
106        SetConfigValue(relativeWidth, 0.8);
107        SetConfigValue(relativeHeight, 0.4);
108        SetConfigValue(blinkTime, 0.5);
109        SetConfigValue(scrollSpeed_, 3.0f);
110        SetConfigValue(noiseSize_, 1.0f);
111        SetConfigValue(cursorSymbol_, '|');
112    }
113
114    /**
115        @brief Initializes the InGameConsole.
116    */
117    void InGameConsole::initialise()
118    {
119        // create the corresponding input state
120        InputManager::createSimpleInputState("console", 40)->setKeyHandler(Shell::getInstance().getInputBuffer());
121
122        // create overlay and elements
123        Ogre::OverlayManager* ovMan = Ogre::OverlayManager::getSingletonPtr();
124
125        // create actual overlay
126        this->consoleOverlay_ = ovMan->create("InGameConsoleConsole");
127
128        // create a container
129        this->consoleOverlayContainer_ = static_cast<Ogre::OverlayContainer*>(ovMan->createOverlayElement("Panel", "InGameConsoleContainer"));
130        this->consoleOverlayContainer_->setMetricsMode(Ogre::GMM_RELATIVE);
131        this->consoleOverlayContainer_->setPosition((1 - this->relativeWidth) / 2, 0);
132        this->consoleOverlayContainer_->setDimensions(this->relativeWidth, this->relativeHeight);
133        this->consoleOverlay_->add2D(this->consoleOverlayContainer_);
134
135        // create BorderPanel
136        this->consoleOverlayBorder_ = static_cast<Ogre::BorderPanelOverlayElement*>(ovMan->createOverlayElement("BorderPanel", "InGameConsoleBorderPanel"));
137        this->consoleOverlayBorder_->setMetricsMode(Ogre::GMM_PIXELS);
138        this->consoleOverlayBorder_->setMaterialName("ConsoleCenter");
139        this->consoleOverlayBorder_->setBorderSize(16, 16, 0, 16);
140        this->consoleOverlayBorder_->setBorderMaterialName("ConsoleBorder");
141        this->consoleOverlayBorder_->setLeftBorderUV(0.0, 0.49, 0.5, 0.51);
142        this->consoleOverlayBorder_->setRightBorderUV(0.5, 0.49, 1.0, 0.5);
143        this->consoleOverlayBorder_->setBottomBorderUV(0.49, 0.5, 0.51, 1.0);
144        this->consoleOverlayBorder_->setBottomLeftBorderUV(0.0, 0.5, 0.5, 1.0);
145        this->consoleOverlayBorder_->setBottomRightBorderUV(0.5, 0.5, 1.0, 1.0);
146        this->consoleOverlayContainer_->addChild(this->consoleOverlayBorder_);
147
148        // create a new font to match the requested size exactly
149        Ogre::FontPtr font = static_cast<Ogre::FontPtr>
150            (Ogre::FontManager::getSingleton().create("MonofurConsole", "General"));
151        font->setType(Ogre::FT_TRUETYPE);
152        font->setSource("Monofur.ttf");
153        font->setTrueTypeSize(18);
154        // reto: I don't know why, but setting the resolution twice as high makes the font look a lot clearer
155        font->setTrueTypeResolution(192);
156        font->addCodePointRange(Ogre::Font::CodePointRange(33, 126));
157        font->addCodePointRange(Ogre::Font::CodePointRange(161, 255));
158
159        // create the text lines
160        this->consoleOverlayTextAreas_ = new Ogre::TextAreaOverlayElement*[LINES];
161        for (int i = 0; i < LINES; i++)
162        {
163            this->consoleOverlayTextAreas_[i] = static_cast<Ogre::TextAreaOverlayElement*>(ovMan->createOverlayElement("TextArea", "InGameConsoleTextArea" + convertToString(i)));
164            this->consoleOverlayTextAreas_[i]->setMetricsMode(Ogre::GMM_PIXELS);
165            this->consoleOverlayTextAreas_[i]->setFontName("MonofurConsole");
166            this->consoleOverlayTextAreas_[i]->setCharHeight(18);
167            this->consoleOverlayTextAreas_[i]->setParameter("colour_top", "0.21 0.69 0.21");
168            this->consoleOverlayTextAreas_[i]->setLeft(8);
169            this->consoleOverlayTextAreas_[i]->setCaption("");
170            this->consoleOverlayContainer_->addChild(this->consoleOverlayTextAreas_[i]);
171        }
172
173        // create cursor (also a text area overlay element)
174        this->consoleOverlayCursor_ = static_cast<Ogre::TextAreaOverlayElement*>(ovMan->createOverlayElement("TextArea", "InGameConsoleCursor"));
175        this->consoleOverlayCursor_->setMetricsMode(Ogre::GMM_PIXELS);
176        this->consoleOverlayCursor_->setFontName("MonofurConsole");
177        this->consoleOverlayCursor_->setCharHeight(18);
178        this->consoleOverlayCursor_->setParameter("colour_top", "0.21 0.69 0.21");
179        this->consoleOverlayCursor_->setLeft(7);
180        this->consoleOverlayCursor_->setCaption(std::string(this->cursorSymbol_, 1));
181        this->consoleOverlayContainer_->addChild(this->consoleOverlayCursor_);
182
183        // create noise
184        this->consoleOverlayNoise_ = static_cast<Ogre::PanelOverlayElement*>(ovMan->createOverlayElement("Panel", "InGameConsoleNoise"));
185        this->consoleOverlayNoise_->setMetricsMode(Ogre::GMM_PIXELS);
186        this->consoleOverlayNoise_->setPosition(5,0);
187        this->consoleOverlayNoise_->setMaterialName("ConsoleNoiseSmall");
188        // comment following line to disable noise
189        this->consoleOverlayContainer_->addChild(this->consoleOverlayNoise_);
190
191        this->windowResized(GraphicsEngine::getSingleton().getWindowWidth(), GraphicsEngine::getSingleton().getWindowHeight());
192
193        // move overlay "above" the top edge of the screen
194        // we take -1.2 because the border makes the panel bigger
195        this->consoleOverlayContainer_->setTop(-1.2 * this->relativeHeight);
196
197        Shell::getInstance().addOutputLevel(true);
198
199        COUT(4) << "Info: InGameConsole initialized" << std::endl;
200    }
201
202    /**
203        @brief Destroys all the elements if necessary.
204    */
205    void InGameConsole::destroy()
206    {
207        this->deactivate();
208
209        // destroy the input state previously created
210        SimpleInputState * inputState = dynamic_cast<SimpleInputState*>(InputManager::getState("console"));
211        if (inputState)
212            InputManager::destroyState("console");
213
214        Ogre::OverlayManager* ovMan = Ogre::OverlayManager::getSingletonPtr();
215        if (ovMan)
216        {
217            if (this->consoleOverlayNoise_)
218                Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayNoise_);
219            if (this->consoleOverlayCursor_)
220                Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayCursor_);
221            if (this->consoleOverlayBorder_)
222                Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayBorder_);
223            if (this->consoleOverlayTextAreas_)
224            {
225                for (int i = 0; i < LINES; i++)
226                {
227                    if (this->consoleOverlayTextAreas_[i])
228                      Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayTextAreas_[i]);
229                    this->consoleOverlayTextAreas_[i] = 0;
230                }
231
232            }
233            if (this->consoleOverlayContainer_)
234                Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayContainer_);
235        }
236        if (this->consoleOverlayTextAreas_)
237        {
238            delete[] this->consoleOverlayTextAreas_;
239            this->consoleOverlayTextAreas_ = 0;
240        }
241    }
242
243    // ###############################
244    // ###  ShellListener methods  ###
245    // ###############################
246
247    /**
248        @brief Called if all output-lines have to be redrawn.
249    */
250    void InGameConsole::linesChanged()
251    {
252        std::list<std::string>::const_iterator it = Shell::getInstance().getNewestLineIterator();
253        int max = 0;
254        for (int i = 1; i < LINES; ++i)
255        {
256            if (it != Shell::getInstance().getEndIterator())
257            {
258                ++it;
259                max = i;
260            }
261            else
262                break;
263        }
264
265        for (int i = LINES - 1; i > max; --i)
266            this->print("", i, true);
267
268        for (int i = max; i >= 1; --i)
269        {
270            --it;
271            this->print(*it, i, true);
272        }
273    }
274
275    /**
276        @brief Called if only the last output-line has changed.
277    */
278    void InGameConsole::onlyLastLineChanged()
279    {
280        if (LINES > 1)
281            this->print(*Shell::getInstance().getNewestLineIterator(), 1);
282    }
283
284    /**
285        @brief Called if a new output-line was added.
286    */
287    void InGameConsole::lineAdded()
288    {
289        this->numLinesShifted_ = 0;
290        this->shiftLines();
291        this->onlyLastLineChanged();
292    }
293
294    /**
295        @brief Called if the text in the input-line has changed.
296    */
297    void InGameConsole::inputChanged()
298    {
299        if (LINES > 0)
300            this->print(Shell::getInstance().getInput(), 0);
301
302        if (Shell::getInstance().getInput() == "" || Shell::getInstance().getInput().size() == 0)
303            this->inputWindowStart_ = 0;
304    }
305
306    /**
307        @brief Called if the position of the cursor in the input-line has changed.
308    */
309    void InGameConsole::cursorChanged()
310    {
311        unsigned int pos = Shell::getInstance().getCursorPosition() - inputWindowStart_;
312        if (pos > maxCharsPerLine_)
313            pos = maxCharsPerLine_;
314        else if (pos < 0)
315            pos = 0;
316
317        this->consoleOverlayCursor_->setCaption(std::string(pos,' ') + cursorSymbol_);
318        this->consoleOverlayCursor_->setTop((int) this->windowH_ * this->relativeHeight - 24);
319    }
320
321    /**
322        @brief Called if the console gets closed.
323    */
324    void InGameConsole::exit()
325    {
326        this->deactivate();
327    }
328
329    // ###############################
330    // ###  other external calls   ###
331    // ###############################
332
333    /**
334        @brief Used to control the actual scrolling and the cursor.
335    */
336    void InGameConsole::tick(float dt)
337    {
338        if (this->scroll_ != 0)
339        {
340            float oldTop = this->consoleOverlayContainer_->getTop();
341
342            if (this->scroll_ > 0)
343            {
344                // scrolling down
345                // enlarge oldTop a little bit so that this exponential function
346                // reaches 0 before infinite time has passed...
347                float deltaScroll = (oldTop - 0.01) * dt * this->scrollSpeed_;
348                if (oldTop - deltaScroll >= 0)
349                {
350                    // window has completely scrolled down
351                    this->consoleOverlayContainer_->setTop(0);
352                    this->scroll_ = 0;
353                }
354                else
355                    this->consoleOverlayContainer_->setTop(oldTop - deltaScroll);
356            }
357
358            else
359            {
360                // scrolling up
361                // note: +0.01 for the same reason as when scrolling down
362                float deltaScroll = (1.2 * this->relativeHeight + 0.01 + oldTop) * dt * this->scrollSpeed_;
363                if (oldTop - deltaScroll <= -1.2 * this->relativeHeight)
364                {
365                    // window has completely scrolled up
366                    this->consoleOverlayContainer_->setTop(-1.2 * this->relativeHeight);
367                    this->scroll_ = 0;
368                    this->consoleOverlay_->hide();
369                }
370                else
371                    this->consoleOverlayContainer_->setTop(oldTop - deltaScroll);
372            }
373        }
374
375        if (this->bActive_)
376        {
377            this->cursor_ += dt;
378            if (this->cursor_ >= this->blinkTime)
379            {
380                this->cursor_ = 0;
381                bShowCursor_ = !bShowCursor_;
382                if (bShowCursor_)
383                    this->consoleOverlayCursor_->show();
384                else
385                    this->consoleOverlayCursor_->hide();
386            }
387
388            // this creates a flickering effect (extracts exactly 80% of the texture at a random location)
389            float uRand = (rand() & 1023) / 1023.0f * 0.2f;
390            float vRand = (rand() & 1023) / 1023.0f * 0.2f;
391            this->consoleOverlayNoise_->setUV(uRand, vRand, 0.8f + uRand, 0.8f + vRand);
392        }
393    }
394
395    /**
396        @brief Resizes the console elements. Call if window size changes.
397    */
398    void InGameConsole::windowResized(int newWidth, int newHeight)
399    {
400        this->windowW_ = newWidth;
401        this->windowH_ = newHeight;
402        this->consoleOverlayBorder_->setWidth((int) this->windowW_* this->relativeWidth);
403        this->consoleOverlayBorder_->setHeight((int) this->windowH_ * this->relativeHeight);
404        this->consoleOverlayNoise_->setWidth((int) this->windowW_ * this->relativeWidth - 10);
405        this->consoleOverlayNoise_->setHeight((int) this->windowH_ * this->relativeHeight - 5);
406        this->consoleOverlayNoise_->setTiling(consoleOverlayNoise_->getWidth() / (50.0f * this->noiseSize_), consoleOverlayNoise_->getHeight() / (50.0f * this->noiseSize_));
407
408        // now adjust the text lines...
409        this->desiredTextWidth_ = (int) (this->windowW_ * this->relativeWidth) - 12;
410
411        if (LINES > 0)
412            this->maxCharsPerLine_ = max((unsigned int)10, (unsigned int) ((float)this->desiredTextWidth_ / CHAR_WIDTH));
413        else
414            this->maxCharsPerLine_ = 10;
415
416        for (int i = 0; i < LINES; i++)
417        {
418            this->consoleOverlayTextAreas_[i]->setWidth(this->desiredTextWidth_);
419            this->consoleOverlayTextAreas_[i]->setTop((int) this->windowH_ * this->relativeHeight - 24 - 14*i);
420        }
421
422        this->linesChanged();
423        this->cursorChanged();
424    }
425
426    // ###############################
427    // ###    internal methods     ###
428    // ###############################
429
430    /**
431        @brief Prints string to bottom line.
432        @param s String to be printed
433    */
434    void InGameConsole::print(const std::string& text, int index, bool alwaysShift)
435    {
436        char level = 0;
437        if (text.size() > 0)
438            level = text[0];
439
440        std::string output = text;
441
442        if (level >= -1 && level <= 5)
443            output.erase(0, 1);
444
445        if (LINES > index)
446        {
447            this->colourLine(level, index);
448
449            if (index > 0)
450            {
451                unsigned int linesUsed = 1;
452                while (output.size() > this->maxCharsPerLine_)
453                {
454                    ++linesUsed;
455                    this->consoleOverlayTextAreas_[index]->setCaption(convert2UTF(output.substr(0, this->maxCharsPerLine_)));
456                    output.erase(0, this->maxCharsPerLine_);
457                    output.insert(0, 1, ' ');
458                    if (linesUsed > numLinesShifted_ || alwaysShift)
459                        this->shiftLines();
460                    this->colourLine(level, index);
461                }
462                this->consoleOverlayTextAreas_[index]->setCaption(convert2UTF(output));
463                this->displayedText_ = output;
464                this->numLinesShifted_ = linesUsed;
465            }
466            else
467            {
468                if (output.size() > this->maxCharsPerLine_)
469                {
470                    if (Shell::getInstance().getInputBuffer()->getCursorPosition() < this->inputWindowStart_)
471                        this->inputWindowStart_ = Shell::getInstance().getInputBuffer()->getCursorPosition();
472                    else if (Shell::getInstance().getInputBuffer()->getCursorPosition() >= (this->inputWindowStart_ + this->maxCharsPerLine_ - 1))
473                        this->inputWindowStart_ = Shell::getInstance().getInputBuffer()->getCursorPosition() - this->maxCharsPerLine_ + 1;
474
475                    output = output.substr(this->inputWindowStart_, this->maxCharsPerLine_);
476                }
477                else
478                  this->inputWindowStart_ = 0;
479                this->displayedText_ = output;
480                this->consoleOverlayTextAreas_[index]->setCaption(convert2UTF(output));
481            }
482        }
483    }
484
485    /**
486        @brief Shows the InGameConsole.
487    */
488    void InGameConsole::activate()
489    {
490        if (!this->bActive_)
491        {
492            this->bActive_ = true;
493            InputManager::requestEnterState("console");
494            Shell::getInstance().registerListener(this);
495
496            this->windowResized(this->windowW_, this->windowH_);
497            this->linesChanged();
498            this->cursorChanged();
499            this->consoleOverlay_->show();
500
501            // scroll down
502            this->scroll_ = 1;
503            // the rest is done by tick
504        }
505    }
506
507    /**
508    @brief Hides the InGameConsole.
509    */
510    void InGameConsole::deactivate()
511    {
512        if (this->bActive_)
513        {
514            this->bActive_ = false;
515            InputManager::requestLeaveState("console");
516            Shell::getInstance().unregisterListener(this);
517
518            // scroll up
519            this->scroll_ = -1;
520            // the rest is done by tick
521        }
522    }
523
524    /**
525        @brief Shifts all output lines one line up
526    */
527    void InGameConsole::shiftLines()
528    {
529        for (unsigned int i = LINES - 1; i > 1; --i)
530        {
531            this->consoleOverlayTextAreas_[i]->setCaption(this->consoleOverlayTextAreas_[i - 1]->getCaption());
532            this->consoleOverlayTextAreas_[i]->setColourTop(this->consoleOverlayTextAreas_[i - 1]->getColourTop());
533            this->consoleOverlayTextAreas_[i]->setColourBottom(this->consoleOverlayTextAreas_[i - 1]->getColourBottom());
534        }
535    }
536
537    void InGameConsole::colourLine(int colourcode, int index)
538    {
539        if (colourcode == -1)
540        {
541            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.90, 0.90, 0.90, 1.00));
542            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(1.00, 1.00, 1.00, 1.00));
543        }
544        else if (colourcode == 1)
545        {
546            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.95, 0.25, 0.25, 1.00));
547            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(1.00, 0.50, 0.50, 1.00));
548        }
549        else if (colourcode == 2)
550        {
551            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.95, 0.50, 0.20, 1.00));
552            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(1.00, 0.70, 0.50, 1.00));
553        }
554        else if (colourcode == 3)
555        {
556            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.50, 0.50, 0.95, 1.00));
557            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(0.80, 0.80, 1.00, 1.00));
558        }
559        else if (colourcode == 4)
560        {
561            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.65, 0.48, 0.44, 1.00));
562            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(1.00, 0.90, 0.90, 1.00));
563        }
564        else if (colourcode == 5)
565        {
566            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.40, 0.20, 0.40, 1.00));
567            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(0.80, 0.60, 0.80, 1.00));
568        }
569        else
570        {
571            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.21, 0.69, 0.21, 1.00));
572            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(0.80, 1.00, 0.80, 1.00));
573        }
574    }
575
576    // ###############################
577    // ###      satic methods      ###
578    // ###############################
579
580    /**
581        @brief Activates the console.
582    */
583    /*static*/ void InGameConsole::openConsole()
584    {
585        InGameConsole::getInstance().activate();
586    }
587
588    /**
589        @brief Deactivates the console.
590    */
591    /*static*/ void InGameConsole::closeConsole()
592    {
593        InGameConsole::getInstance().deactivate();
594    }
595
596    /**
597        @brief Converts a string into an Ogre::UTFString.
598        @param s The string to convert
599        @return The converted string
600    */
601    /*static*/ Ogre::UTFString InGameConsole::convert2UTF(std::string s)
602    {
603        Ogre::UTFString utf;
604        Ogre::UTFString::code_point cp;
605        for (unsigned int i = 0; i < s.size(); ++i)
606        {
607          cp = s[i];
608          cp &= 0xFF;
609          utf.append(1, cp);
610        }
611        return utf;
612    }
613}
Note: See TracBrowser for help on using the repository browser.