Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/orxonox/console/InGameConsole.cc @ 1494

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