glut-font-effects.cpp

Go to the documentation of this file.
00001 /*
00002  * glut-font-effects.cpp
00003  *
00004  * Copyright (C) 2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  * Some font effects.  See glut-font-effects.h
00031  */
00032 
00033 // includes --------------------------------------------------------------------
00034 #include "glut-font-effects.h"          // always include our own header first
00035 
00036 #include "glut/glut.h"
00037 #include "perf/perf.h"
00038 #include "util/parsing.h"
00039 
00040 
00041 namespace glut {
00042 
00043 
00044 // interface destructors
00045 FontEffect::~FontEffect(void) throw() { }
00046 
00047 
00048 ////////////////////////////////////////////////////////////////////////////////
00049 //
00050 //      static helper methods
00051 //
00052 ////////////////////////////////////////////////////////////////////////////////
00053 
00054 
00055 ////////////////////////////////////////////////////////////////////////////////
00056 //
00057 //      CharStep - class that implements glut::FontEffect and advances lines one
00058 //      character at a time.
00059 //
00060 ////////////////////////////////////////////////////////////////////////////////
00061 
00062 class CharStep : public FontEffect {
00063 public:
00064         ~CharStep(void) throw() { }
00065 
00066         // public class methods ------------------------------------------------
00067         void initialize(IN smart_ptr<Font>& font,
00068                                 IN const char * lines,
00069                                 IN int msPerChar,
00070                                 IN const glut_color_t& color);
00071 
00072         // glut::FontEffect class interface methods ----------------------------
00073         void tick(IN float deltaT);
00074         void render(void);
00075         void reset(void);
00076         void advance(void);
00077         void complete(void);
00078 
00079 private:
00080         // private typedefs ----------------------------------------------------
00081         // private helper methods ----------------------------------------------
00082         utf8_char_t addChar(void);
00083 
00084         // private member data -------------------------------------------------
00085         smart_ptr<Font>         m_font;
00086         glut_color_t            m_color;
00087         std::string             m_text;
00088         VecString               m_lines;
00089         int                     m_msPerChar;
00090         float                   m_time;
00091         const char *            m_curr;
00092         int                     m_currLine;
00093 };
00094 
00095 
00096 
00097 void
00098 CharStep::initialize
00099 (
00100 IN smart_ptr<Font>& font,
00101 IN const char * lines,
00102 IN int msPerChar,
00103 IN const glut_color_t& color
00104 )
00105 {
00106         ASSERT(font, "null");
00107         ASSERT(lines, "null");
00108         ASSERT(msPerChar >= 0, "Bad ms per character: %d", msPerChar);
00109 
00110         m_font = font;
00111         m_color = color;
00112         m_time = 0.0;
00113         m_msPerChar = msPerChar;
00114 
00115         // save raw lines
00116         m_text = lines;
00117 
00118         this->reset();
00119 }
00120 
00121 
00122 
00123 void
00124 CharStep::tick
00125 (
00126 IN float deltaT
00127 )
00128 {
00129         if (deltaT <= 0.0 || !m_curr)
00130                 return;         // do nothing!
00131         m_time += deltaT;
00132 
00133 //      DPRINTF("m_time = %f", m_time);
00134         int nChars = (int) (1000.0 * m_time / m_msPerChar);
00135         m_time -= 0.001 * nChars * m_msPerChar;
00136 //      DPRINTF("  nChars = %d", nChars);
00137 
00138         // add these characters to our buffers
00139         for (int i = 0; i < nChars; ++i) {
00140                 this->addChar();
00141         }
00142 }
00143 
00144 
00145 
00146 void
00147 CharStep::render
00148 (
00149 void
00150 )
00151 {
00152         ASSERT(m_font, "null");
00153 
00154         glColor4f(m_color.red, m_color.green, m_color.blue, m_color.alpha);
00155 
00156         int dy = m_font->getLineHeight() + 2;
00157 
00158         int nLines = m_lines.size();
00159         for (int i = 0; i < nLines; ++i) {
00160                 const char * line = m_lines[i].c_str();
00161                 m_font->display(0, 0, 0, line);
00162                 glTranslatef(0, dy, 0);
00163         }
00164 }
00165 
00166 
00167 
00168 void
00169 CharStep::advance
00170 (
00171 void
00172 )
00173 {
00174         while (true) {
00175                 utf8_char_t c = this->addChar();
00176                 if (!c || c == '\n')
00177                         return;
00178         }
00179 }
00180 
00181 
00182 
00183 void
00184 CharStep::complete
00185 (
00186 void
00187 )
00188 {
00189         while (this->addChar()) { }
00190 }
00191 
00192 
00193 
00194 void
00195 CharStep::reset
00196 (
00197 void
00198 )
00199 {
00200         // start back at beginning of input text
00201         m_curr = m_text.c_str();
00202 
00203         // clear array of lines
00204         m_lines.clear();
00205 
00206         // start with new empty line
00207         m_lines.push_back("");
00208         m_currLine = 0;
00209 }
00210 
00211 
00212 
00213 utf8_char_t
00214 CharStep::addChar
00215 (
00216 void
00217 )
00218 {
00219         utf8_char_t c;
00220         if (!m_curr)
00221                 return c;       // end of input characters!
00222 
00223         m_curr = getUTF8CharacterFromString(m_curr, c);
00224         if (c.nBytes < 1) {
00225                 DPRINTF("Bad UTF8 character in string?");
00226                 m_curr = NULL;  // stop parsing...
00227                 return c;
00228         }
00229         if (0 == c.value[0]) {
00230                 // end of input text
00231                 m_curr = NULL;
00232         } else if ('\n' == c.value[0]) {
00233                 // newline!
00234                 m_currLine++;
00235                 m_lines.push_back("");  // new empty line
00236         } else {
00237                 // append to line
00238                 const char * line = m_lines[m_currLine].c_str();
00239                 std::string newLine = line;
00240                 newLine += c.value;     // multibyte
00241 //              DPRINTF("Line: '%s'", newLine.c_str());
00242                 m_lines[m_currLine] = newLine;
00243         }
00244 
00245         return c;
00246 }
00247 
00248 
00249 
00250 ////////////////////////////////////////////////////////////////////////////////
00251 //
00252 //      public API
00253 //
00254 ////////////////////////////////////////////////////////////////////////////////
00255 
00256 smart_ptr<FontEffect>
00257 getCharacterAdvanceEffect
00258 (
00259 IN smart_ptr<Font>& font,
00260 IN const char * lines,
00261 IN int millisecondsPerCharacter,
00262 IN const glut_color_t& color
00263 )
00264 {
00265         ASSERT(font, "null");
00266         ASSERT(lines, "null");
00267         ASSERT(millisecondsPerCharacter >= 0, "bad milliseconds: %d",
00268             millisecondsPerCharacter);
00269 
00270         smart_ptr<CharStep> local = new CharStep;
00271         ASSERT(local, "out of memory");
00272 
00273         local->initialize(font, lines, millisecondsPerCharacter, color);
00274 
00275         return local;
00276 }
00277 
00278 
00279 
00280 void
00281 breakLongString
00282 (
00283 IN const char * text,
00284 IN Font * font,
00285 IN int maxPixelWidth,
00286 OUT std::string& out
00287 )
00288 {
00289         ASSERT(text, "null");
00290         ASSERT(font, "null");
00291         out.clear();
00292 
00293         // keep looping through lines
00294         std::string line;
00295         while (*text) {
00296                 std::string word;
00297 
00298                 // keep parsing words
00299                 text = getNextWord(text, word);
00300                 if ("\n" == word) {
00301                         // next line
00302                         out += line;
00303                         out += "\n";
00304                         line.clear();
00305                 } else if ("" == line) {
00306                         // line is empty, so line now becomes word
00307                         line = word;
00308                 } else {
00309                         // see if we can add word to non-empty line
00310                         std::string candidate_line = line;
00311                         candidate_line += " ";
00312                         candidate_line += word;
00313 
00314                         // how long is this line?
00315                         font_rect_t fr =
00316                             font->getBoundingRect(candidate_line.c_str());
00317                         int width = fr.lead + fr.trail;
00318                         if (width > maxPixelWidth) {
00319                                 // line is too long!
00320                                 if ("" != line) {
00321                                         out += line;
00322                                         out += "\n";
00323                                 }
00324                                 line = word;
00325                         } else {
00326                                 // line is within bounds
00327                                 line = candidate_line;
00328                         }
00329                 }
00330         }
00331 
00332         if (!line.empty()) {
00333                 out += line;
00334         }
00335 }
00336 
00337 
00338 
00339 };      // glut namespace
00340