Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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