/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... */ //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_ #include "shell.h" #include "shell_command.h" #include "shell_buffer.h" #include "shell_input.h" #include "text.h" #include "graphics_engine.h" #include "material.h" #include "event_handler.h" #include "debug.h" #include "class_list.h" #include "key_names.h" #include #include using namespace std; SHELL_COMMAND(clear, Shell, clear) ->describe("Clears the shell from unwanted lines (empties all buffers)") ->setAlias("clear"); SHELL_COMMAND(deactivate, Shell, deactivate) ->describe("Deactivates the Shell. (moves it into background)") ->setAlias("hide"); SHELL_COMMAND(textsize, Shell, setTextSize) ->describe("Sets the size of the Text size, linespacing") ->defaultValues(15, 0); SHELL_COMMAND(textcolor, Shell, setTextColor) ->describe("Sets the Color of the Shells Text (red, green, blue, alpha)") ->defaultValues(SHELL_DEFAULT_TEXT_COLOR); SHELL_COMMAND(backgroundcolor, Shell, setBackgroundColor) ->describe("Sets the Color of the Shells Background (red, green, blue, alpha)") ->defaultValues(SHELL_DEFAULT_BACKGROUND_COLOR); SHELL_COMMAND(backgroundimage, Shell, setBackgroundImage) ->describe("sets the background image to load for the Shell"); SHELL_COMMAND(font, Shell, setFont) ->describe("Sets the font of the Shell") ->defaultValues(SHELL_DEFAULT_FONT); /** * standard constructor */ Shell::Shell () { this->setClassID(CL_SHELL, "Shell"); this->setName("Shell"); // EVENT-Handler subscription of '`' to all States. EventHandler::getInstance()->subscribe(this, ES_ALL, SDLK_BACKQUOTE); EventHandler::getInstance()->subscribe(this, ES_ALL, SDLK_F12); EventHandler::getInstance()->subscribe(this, ES_SHELL, SDLK_PAGEUP); EventHandler::getInstance()->subscribe(this, ES_SHELL, SDLK_PAGEDOWN); // BUFFER this->bufferText = NULL; this->bufferDisplaySize = 10; this->bufferOffset = 0; this->bufferIterator = ShellBuffer::getInstance()->getBuffer()->begin(); // INPUT LINE this->shellInput = new ShellInput; this->backgroundMaterial = new Material; // Element2D and generals this->setAbsCoor2D(3, -400); this->textSize = 20; this->lineSpacing = 0; this->bActive = true; this->fontFile = new char[strlen(SHELL_DEFAULT_FONT)+1]; strcpy(this->fontFile, SHELL_DEFAULT_FONT); this->rebuildText(); this->setTextColor(SHELL_DEFAULT_TEXT_COLOR); this->setBackgroundColor(SHELL_DEFAULT_BACKGROUND_COLOR); this->deactivate(); // register the shell at the ShellBuffer ShellBuffer::getInstance()->registerShell(this); } /** * standard deconstructor */ Shell::~Shell () { ShellBuffer::getInstance()->unregisterShell(this); // delete the displayable Buffers for (unsigned int i = 0; i < this->bufferDisplaySize; i++) delete this->bufferText[i]; delete[] this->bufferText; delete[] this->fontFile; // delete the inputLine delete this->shellInput; delete this->backgroundMaterial; } /** * activates the shell * * This also feeds the Last few lines from the main buffers into the displayBuffer */ void Shell::activate() { if (this->bActive == true) PRINTF(3)("The shell is already active\n"); this->bActive = true; EventHandler::getInstance()->pushState(ES_SHELL); EventHandler::getInstance()->withUNICODE(true); this->setRelCoorSoft2D(0, 0, 1, 5); list::const_iterator textLine = --ShellBuffer::getInstance()->getBuffer()->end(); bool top = false; for (int i = 0; i < this->bufferDisplaySize; i++) { this->bufferText[i]->setVisibility(true); if (!top) { this->bufferText[i]->setText((*textLine), true); if (textLine != ShellBuffer::getInstance()->getBuffer()->begin()) top = true; textLine--; } } } /** * deactiveates the Shell. */ void Shell::deactivate() { if (this->bActive == false) PRINTF(3)("The shell is already inactive\n"); this->bActive = false; EventHandler::getInstance()->withUNICODE(false); EventHandler::getInstance()->popState(); this->setRelCoorSoft2D(0, -(int)this->shellHeight, 1, 5); list::const_iterator textLine = --ShellBuffer::getInstance()->getBuffer()->end(); for (int i = 0; i < this->bufferDisplaySize; i++) { this->bufferText[i]->setVisibility(false); if (textLine != ShellBuffer::getInstance()->getBuffer()->begin()) { this->bufferText[i]->setText((*textLine), false); textLine--; } } this->bufferOffset = 0; } /** * sets the File to load the fonts from * @param fontFile the file to load the font from * * it is quite important, that the font pointed too really exists! * (be aware that within orxonox fontFile is relative to the Data-Dir) */ void Shell::setFont(const char* fontFile) { // if (!ResourceManager::isInDataDir(fontFile)) // return false; if (this->fontFile != NULL) delete[] this->fontFile; this->fontFile = new char[strlen(fontFile)+1]; strcpy(this->fontFile, fontFile); this->rebuildText(); } /** * sets the size of the text and spacing * @param textSize the size of the Text in Pixels * @param lineSpacing the size of the Spacing between two lines in pixels * * this also rebuilds the entire Text, inputLine and displayBuffer, * to be accurate again. */ void Shell::setTextSize(unsigned int textSize, unsigned int lineSpacing) { this->textSize = textSize; this->lineSpacing = lineSpacing; this->resetValues(); } /** * sets the color of the Font. * @param r: red * @param g: green * @param b: blue * @param a: alpha-value. */ void Shell::setTextColor(float r, float g, float b, float a) { this->textColor[0] = r; this->textColor[1] = g; this->textColor[2] = b; this->textColor[3] = a; this->resetValues(); } /** * sets the color of the Backgrond. * @param r: red * @param g: green * @param b: blue * @param a: alpha-value. */ void Shell::setBackgroundColor(float r, float g, float b, float a) { this->backgroundMaterial->setDiffuse(r, g, b); this->backgroundMaterial->setTransparency(a); } /** * sets a nice background image to the Shell's background * @param fileName the filename of the Image to load */ void Shell::setBackgroundImage(const char* fileName) { this->backgroundMaterial->setDiffuseMap(fileName); } /** * resets the Values of all visible shell's commandos to the Shell's stored values * * this functions synchronizes the stored Data with the visible one. */ void Shell::resetValues() { if (this->shellInput != NULL) { this->shellInput->setSize(this->textSize); this->shellInput->setColor(this->textColor[0], this->textColor[1], this->textColor[2]); this->shellInput->setBlending(this->textColor[3]); this->shellInput->setRelCoor2D(5, (this->textSize + this->lineSpacing)*(this->bufferDisplaySize)); } if (this->bufferText != NULL) { for (unsigned int i = 0; i < this->bufferDisplaySize; i++) { if (this->bufferText[i] != NULL) { this->bufferText[i]->setSize(this->textSize); this->bufferText[i]->setColor(this->textColor[0], this->textColor[1], this->textColor[2]); this->bufferText[i]->setBlending(this->textColor[3]); this->bufferText[i]->setRelCoor2D(calculateLinePosition(i)); } } } this->shellHeight = (this->textSize + this->lineSpacing) * (bufferDisplaySize+1); } /** * rebuilds the Text's * * use this function, if you changed the Font/Size or something else. */ void Shell::rebuildText() { this->shellInput->setFont(this->fontFile, this->textSize); this->shellInput->setAlignment(TEXT_ALIGN_LEFT); if (shellInput->getParent2D() != this) this->shellInput->setParent2D(this); this->setBufferDisplaySize(this->bufferDisplaySize); } /** * sets The count of Lines to display in the buffer. * @param bufferDisplaySize the count of lines to display in the Shell-Buffer. */ void Shell::setBufferDisplaySize(unsigned int bufferDisplaySize) { Text** bufferText = this->bufferText; this->bufferText = NULL; if (bufferText != NULL) { for (unsigned int i = 0; i < this->bufferDisplaySize; i++) delete bufferText[i]; delete[] bufferText; } list::const_iterator textLine = --ShellBuffer::getInstance()->getBuffer()->end(); bufferText = new Text*[bufferDisplaySize]; for (unsigned int i = 0; i < bufferDisplaySize; i++) { bufferText[i] = new Text(this->fontFile, this->textSize); bufferText[i]->setAlignment(TEXT_ALIGN_LEFT); bufferText[i]->setParent2D(this); if(textLine != ShellBuffer::getInstance()->getBuffer()->begin()) { bufferText[i]->setText(*textLine); textLine--; } } this->bufferDisplaySize = bufferDisplaySize; this->bufferText = bufferText; this->shellHeight = (this->textSize + this->lineSpacing) * (bufferDisplaySize+1); } /** * deletes all the Buffers */ void Shell::flush() { // remove all chars from the BufferTexts. if (this->bufferText != NULL) for (int i = 0; i < this->bufferDisplaySize; i++) { this->bufferText[i]->setText(NULL, true); } ShellBuffer::getInstance()->flush(); // BUFFER FLUSHING } /** * prints out some text to the input-buffers * @param text the text to output. */ void Shell::printToDisplayBuffer(const char* text) { if(likely(bufferText != NULL)) { Text* lastText = this->bufferText[this->bufferDisplaySize-1]; Text* swapText; Text* moveText = this->bufferText[0]; for (unsigned int i = 0; i < this->bufferDisplaySize; i++) { if ( i < this->bufferDisplaySize-1) this->bufferText[i]->setRelCoorSoft2D(this->calculateLinePosition(i+1), 5); swapText = this->bufferText[i]; this->bufferText[i] = moveText; moveText = swapText; } /* FANCY EFFECTS :) 1: lastText->setRelCoor2D(this->calculateLinePosition(0)- Vector(-1000,0,0)); lastText->setRelCoorSoft2D(this->calculateLinePosition(0),10); 2: */ lastText->setRelDir2D(-90); lastText->setRelDirSoft2D(0, 20); lastText->setRelCoor2D(this->calculateLinePosition(0)- Vector(-1000,0,0)); lastText->setRelCoorSoft2D(this->calculateLinePosition(0),10); // lastText->setRelCoor2D(this->calculateLinePosition(0)); this->bufferText[0] = lastText; this->bufferText[0]->setText(text, true); } } /** * moves the Display buffer (up + or down - ) * @param lineCount the count by which to shift the InputBuffer. * * @todo make this work */ void Shell::moveDisplayBuffer(int lineCount) { if (this->bufferOffset == 0) { this->bufferIterator = ShellBuffer::getInstance()->getBuffer()->end(); // for (unsigned int i = 0; i < this->bufferDisplaySize; i++) // this->bufferIterator->prevStep(); } // boundraries if (this->bufferOffset + lineCount > (int)ShellBuffer::getInstance()->getBuffer()->size()) lineCount = (int)ShellBuffer::getInstance()->getBuffer()->size()- this->bufferOffset; else if (this->bufferOffset + lineCount < 0) lineCount = -bufferOffset; this->bufferOffset += lineCount; // moving the iterator to the right position int move = 0; while (move != lineCount) { if (move < lineCount) { ++move; this->bufferIterator--; } else { --move; this->bufferIterator++; } } // redisplay the buffers list::const_iterator it = this->bufferIterator; for (unsigned int i = 0; i < this->bufferDisplaySize; i++) { this->bufferText[i]->setText((*it), false); it--; } } /** * clears the Shell (empties all buffers) */ void Shell::clear() { this->flush(); ShellBuffer::addBufferLineStatic("orxonox - shell\n ==================== \n", NULL); } /** * listens for some event * @param event the Event happened */ void Shell::process(const Event &event) { if (event.bPressed) { if (event.type == SDLK_BACKQUOTE || event.type == SDLK_F12) { if (this->bActive == false) this->activate(); else this->deactivate(); } else if (event.type == SDLK_PAGEUP) { this->moveDisplayBuffer(+this->bufferDisplaySize-1); } else if (event.type == SDLK_PAGEDOWN) { this->moveDisplayBuffer(-this->bufferDisplaySize+1); } } } /** * displays the Shell */ void Shell::draw() const { // transform for alignment. // setting the Blending effects this->backgroundMaterial->select(); glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(0, 0); glVertex2f(this->getAbsCoor2D().x, this->getAbsCoor2D().y ); glTexCoord2f(1, 0); glVertex2f(GraphicsEngine::getInstance()->getResolutionX() - this->getAbsCoor2D().x, this->getAbsCoor2D().y ); glTexCoord2f(0, 1); glVertex2f(this->getAbsCoor2D().x, this->getAbsCoor2D().y + this->shellHeight); glTexCoord2f(1, 1); glVertex2f(GraphicsEngine::getInstance()->getResolutionX() - this->getAbsCoor2D().x, this->getAbsCoor2D().y + this->shellHeight); glEnd(); } /////////////////////// // HELPER FUNCTIONS // /////////////////////// /** * calculates the position of a Buffer-Display Line * @param lineNumber the lineNumber from the bottom to calculate the position from * @returns the Position of the Line. */ Vector Shell::calculateLinePosition(unsigned int lineNumber) { return Vector(5, (this->textSize + this->lineSpacing)*(this->bufferDisplaySize - lineNumber - 2) + this->textSize, 0); } /** * displays some nice output from the Shell */ void Shell::debug() const { PRINT(3)("Debugging output to console (not this shell)\n"); // if (this->pressedKey != SDLK_FIRST) // printf("%s::%f %f\n", SDLKToKeyname(this->pressedKey), this->delayed, this->repeatDelay); ShellBuffer::getInstance()->debug(); } // void Shell::testI (int i) // { // PRINTF(3)("This is the Test for one Int '%d'\n", i); // } // // void Shell::testS (const char* s) // { // PRINTF(3)("This is the Test for one String '%s'\n", s); // } // // void Shell::testB (bool b) // { // PRINTF(3)("This is the Test for one Bool: "); // if (b) // PRINTF(3)("true\n"); // else // PRINTF(3)("false\n"); // } // // void Shell::testF (float f) // { // PRINTF(3)("This is the Test for one Float '%f'\n", f); // } // // void Shell::testSF (const char* s, float f) // { // PRINTF(3)("This is the Test for one String '%s' and one Float '%f'\n",s , f); // }