Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/hud/src/orxonox/console/InGameConsole.cc @ 1590

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

svn save, just in case our house burns down over night…

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