Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

console.cpp

Go to the documentation of this file.
00001 // console.cpp
00002 //
00003 // Copyright (C) 2003, Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 #include <cstdarg>
00011 #include <cstdio>
00012 #include <cassert>
00013 #include "celutil/utf8.h"
00014 #include "gl.h"
00015 #include "vecgl.h"
00016 #include "console.h"
00017 
00018 using namespace std;
00019 
00020 
00021 static int pmod(int n, int m)
00022 {
00023     return n >= 0 ? n % m : m - (-(n + 1) % m) - 1;
00024 }
00025 
00026 
00027 Console::Console(int _nRows, int _nColumns) :
00028     ostream(&sbuf),
00029     text(NULL),
00030     nRows(_nRows),
00031     nColumns(_nColumns),
00032     row(0),
00033     column(0),
00034     windowRow(0),
00035     windowHeight(10),
00036     xscale(1),
00037     yscale(1),
00038     font(NULL),
00039     autoScroll(true)
00040 {
00041     sbuf.setConsole(this);
00042     text = new wchar_t[(nColumns + 1) * nRows];
00043     for (int i = 0; i < nRows; i++)
00044         text[(nColumns + 1) * i] = '\0';
00045 }
00046 
00047 
00048 Console::~Console()
00049 {
00050     if (text != NULL)
00051         delete[] text;
00052 }
00053 
00054 
00055 void Console::begin()
00056 {
00057     glMatrixMode(GL_PROJECTION);
00058     glPushMatrix();
00059     glLoadIdentity();
00060     gluOrtho2D(0, xscale, 0, yscale);
00061     glMatrixMode(GL_MODELVIEW);
00062     glPushMatrix();
00063     glLoadIdentity();
00064     glTranslatef(0.125f, 0.125f, 0);
00065 
00066     glDisable(GL_LIGHTING);
00067     glDisable(GL_TEXTURE_2D);
00068     glEnable(GL_BLEND);
00069     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00070 }
00071 
00072 
00073 void Console::end()
00074 {
00075     glMatrixMode(GL_PROJECTION);
00076     glPopMatrix();
00077     glMatrixMode(GL_MODELVIEW);
00078     glPopMatrix();
00079 }
00080 
00081 
00082 void Console::render(int rowHeight)
00083 {
00084     if (font == NULL)
00085         return;
00086 
00087     glEnable(GL_TEXTURE_2D);
00088     font->bind();
00089     glPushMatrix();
00090     for (int i = 0; i < rowHeight; i++)
00091     {
00092         //int r = (nRows - rowHeight + 1 + windowRow + i) % nRows;
00093         int r = pmod(row + windowRow + i, nRows);
00094         for (int j = 0; j < nColumns; j++)
00095         {
00096             wchar_t ch = text[r * (nColumns + 1) + j];
00097             if (ch == '\0')
00098                 break;
00099             font->render(ch);
00100         }
00101 
00102         // advance to the next line
00103         glPopMatrix();
00104         glTranslatef(0.0f, -(1.0f + font->getHeight()), 0.0f);
00105         glPushMatrix();
00106     }
00107     glPopMatrix();
00108 }
00109 
00110 
00111 void Console::setScale(int w, int h)
00112 {
00113     xscale = w;
00114     yscale = h;
00115 }
00116 
00117 
00118 void Console::setFont(TextureFont* f)
00119 {
00120     if (f != font)
00121     {
00122         font = f;
00123     }
00124 }
00125 
00126 
00127 void Console::newline()
00128 {
00129     assert(column <= nColumns);
00130     assert(row < nRows);
00131 
00132     text[row * (nColumns + 1) + column] = '\0';
00133     row = (row + 1) % nRows;
00134     column = 0;
00135 
00136     if (autoScroll)
00137         windowRow = -windowHeight;
00138 }
00139 
00140 void Console::print(wchar_t c)
00141 {
00142     switch (c)
00143     {
00144     case '\n':
00145         newline();
00146         break;
00147     default:
00148         if (column == nColumns)
00149             newline();
00150         text[row * (nColumns + 1) + column] = c;
00151         column++;
00152         break;
00153     }
00154 }
00155 
00156 
00157 void Console::print(char* s)
00158 {
00159     int length = strlen(s);
00160     bool validChar = true;
00161     int i = 0;
00162 
00163     while (i < length && validChar)
00164     {
00165         wchar_t ch = 0;
00166         validChar = UTF8Decode(s, i, length, ch);
00167         i += UTF8EncodedSize(ch);
00168         print(ch);
00169     }
00170 }
00171 
00172 
00173 #if 0
00174 void Console::printf(const char* format, ...)
00175 {
00176     va_list args;
00177     va_start(args, format);
00178 
00179     char buf[1024];
00180     vsprintf(buf, format, args);
00181     print(buf);
00182     
00183     va_end(args);
00184 }
00185 #endif
00186 
00187 
00188 int Console::getRow() const
00189 {
00190     return row;
00191 }
00192 
00193 
00194 int Console::getColumn() const
00195 {
00196     return column;
00197 }
00198 
00199 
00200 int Console::getWindowRow() const
00201 {
00202     return windowRow;
00203 }
00204 
00205 
00206 void Console::setWindowRow(int _row)
00207 {
00208     windowRow = _row;
00209 }
00210 
00211 
00212 void Console::setWindowHeight(int _height)
00213 {
00214     windowHeight = _height;
00215 }
00216 
00217 
00218 int Console::getWidth() const
00219 {
00220     return nColumns;
00221 }
00222 
00223 
00224 int Console::getHeight() const
00225 {
00226     return nRows;
00227 }
00228 
00229 
00230 //
00231 // ConsoleStreamBuf implementation
00232 //
00233 void ConsoleStreamBuf::setConsole(Console* c)
00234 {
00235     console = c;
00236 }
00237 
00238 int ConsoleStreamBuf::overflow(int c)
00239 {
00240     if (console != NULL)
00241     {
00242         switch (decodeState)
00243         {
00244         case UTF8DecodeStart:
00245             if (c < 0x80)
00246             {
00247                 // Just a normal 7-bit character
00248                 console->print((char) c);
00249             }
00250             else
00251             {
00252                 unsigned int count;
00253 
00254                 if ((c & 0xe0) == 0xc0)
00255                     count = 2;
00256                 else if ((c & 0xf0) == 0xe0)
00257                     count = 3;
00258                 else if ((c & 0xf8) == 0xf0)
00259                     count = 4;
00260                 else if ((c & 0xfc) == 0xf8)
00261                     count = 5;
00262                 else if ((c & 0xfe) == 0xfc)
00263                     count = 6;
00264                 else
00265                     count = 1; // Invalid byte
00266 
00267                 if (count > 1)
00268                 {
00269                     unsigned int mask = (1 << (7 - count)) - 1;
00270                     decodeShift = (count - 1) * 6;
00271                     decodedChar = (c & mask) << decodeShift;
00272                     decodeState = UTF8DecodeMultibyte;
00273                 }
00274                 else
00275                 {
00276                     // If the character isn't valid multibyte sequence head,
00277                     // silently skip it by leaving the decoder state alone.
00278                 }
00279             }
00280             break;
00281 
00282         case UTF8DecodeMultibyte:
00283             if ((c & 0xc0) == 0x80)
00284             {
00285                 // We have a valid non-head byte in the sequence
00286                 decodeShift -= 6;
00287                 decodedChar |= (c & 0x3f) << decodeShift;
00288                 if (decodeShift == 0)
00289                 {
00290                     console->print(decodedChar);
00291                     decodeState = UTF8DecodeStart;
00292                 }
00293             }
00294             else
00295             {
00296                 // Bad byte in UTF-8 encoded sequence; we'll silently ignore
00297                 // it and reset the state of the UTF-8 decoder.
00298                 decodeState = UTF8DecodeStart;
00299             }
00300             break;
00301         }
00302     }
00303 
00304     return c;
00305 }

Generated on Sat Jan 14 22:30:27 2006 for Celestia by  doxygen 1.4.1