From 6fe0ea2b24636ef84f13c0565af3ed7e7ea5e176 Mon Sep 17 00:00:00 2001
From: Tamir Atias <engine.games@gmail.com>
Date: Thu, 5 Jan 2012 07:19:29 +0200
Subject: [PATCH] [ADD] Multi-line text rendering.

---
 Win32/Unuk/LibUnuk/LibUnuk.vcproj |   8 ++
 src/Unuk/Player.cpp               |   2 +-
 src/libUnuk/Text.cpp              | 226 ++++++++++++++++++++++++------
 src/libUnuk/Text.h                |   7 +-
 4 files changed, 193 insertions(+), 50 deletions(-)

diff --git a/Win32/Unuk/LibUnuk/LibUnuk.vcproj b/Win32/Unuk/LibUnuk/LibUnuk.vcproj
index 171c9e2..075a7c6 100644
--- a/Win32/Unuk/LibUnuk/LibUnuk.vcproj
+++ b/Win32/Unuk/LibUnuk/LibUnuk.vcproj
@@ -269,6 +269,14 @@
 			RelativePath="..\..\..\src\libUnuk\MapTile.h"
 			>
 		</File>
+		<File
+			RelativePath="..\..\..\src\libUnuk\MemManager.cpp"
+			>
+		</File>
+		<File
+			RelativePath="..\..\..\src\libUnuk\MemManager.h"
+			>
+		</File>
 		<File
 			RelativePath="..\..\..\src\libUnuk\NPC.cpp"
 			>
diff --git a/src/Unuk/Player.cpp b/src/Unuk/Player.cpp
index c49b686..af84aa6 100644
--- a/src/Unuk/Player.cpp
+++ b/src/Unuk/Player.cpp
@@ -57,7 +57,7 @@ void Player::HandleInput(void) {
 
 void Player::Update(void) {
   Move();
-  AddSpeachBubble("Woot, My name is Allanis, welcome to my home");
+  AddSpeachBubble("Woot, My name is Allanis\n, welcome to my home");
 
   // For now The camera will be static.
   SetCamera();
diff --git a/src/libUnuk/Text.cpp b/src/libUnuk/Text.cpp
index fad9cd6..5341714 100644
--- a/src/libUnuk/Text.cpp
+++ b/src/libUnuk/Text.cpp
@@ -6,14 +6,21 @@ TTF_Font* Text::mediumFont   = NULL;
 TTF_Font* Text::largeFont    = NULL;
 TTF_Font* Text::vLargeFont   = NULL;
 
+const static int lineSpacing = 3;
+
 Text::Text(void) {
-  _text = NULL;
+  x=0;
+  y=0;
+  w=0;
+  h=0;
 }
 
 Text::~Text(void) {
-  if (_text) {
-	SDL_FreeSurface(_text);
-	_text = NULL;
+  if(!_lines.empty()) {
+    for(std::list<SDL_Surface*>::iterator it = _lines.begin(); it != _lines.end(); ++it) {
+      SDL_FreeSurface(*it);
+    }
+    _lines.clear();
   }
 }
 
@@ -55,29 +62,83 @@ void Text::SetXY(int xArg, int yArg) {
 int Text::SetTextBlended(string textArg, textSizes_t size, SDL_Color colour) {
   _textContents = textArg;
 
-  if(_text != NULL) {
-    SDL_FreeSurface(_text);
+  if(!_lines.empty()) {
+    for(std::list<SDL_Surface*>::iterator it = _lines.begin(); it != _lines.end(); ++it) {
+      SDL_FreeSurface(*it);
+    }
+    _lines.clear();
+  }
+  
+  std::list<std::string> lines;
+  std::string line;
+  for(int i = 0; i < (int)textArg.size(); i++) {
+    char c = textArg.at(i);
+    if(c=='\n') {
+      lines.push_back(line);
+      line.clear();
+    } else {
+      line += c;
+    }
+  }
+  if (!line.empty()) {
+    lines.push_back(line);
   }
 
-  if(size == vsmall) {
-    _text = TTF_RenderText_Blended(vSmallFont, textArg.c_str(), colour);
-    return 1;
-  }
-  else if(size == small) {
-    _text = TTF_RenderText_Blended(smallFont, textArg.c_str(), colour);
-    return 1;
-  }
-  else if(size == medium) {
-    _text = TTF_RenderText_Blended(mediumFont, textArg.c_str(), colour);
-    return 1;
-  }
-  else if(size == large) {
-    _text = TTF_RenderText_Blended(largeFont, textArg.c_str(), colour);
-    return 1;
-  } else {
-    _text = TTF_RenderText_Blended(vLargeFont, textArg.c_str(), colour);
-    return 1;
+  for(std::list<std::string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+    SDL_Surface* lineSurf = NULL;
+    if(size == vsmall) {
+      lineSurf = TTF_RenderText_Blended(vSmallFont, textArg.c_str(), colour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(vSmallFont, textArg.c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    }
+    else if(size == small) {
+      lineSurf = TTF_RenderText_Blended(smallFont, it->c_str(), colour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(smallFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    }
+    else if(size == medium) {
+      lineSurf = TTF_RenderText_Blended(mediumFont, it->c_str(), colour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(mediumFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    }
+    else if(size == large) {
+      lineSurf = TTF_RenderText_Blended(largeFont, it->c_str(), colour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(largeFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    } else {
+      lineSurf = TTF_RenderText_Blended(vLargeFont, it->c_str(), colour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(vLargeFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    }
+    _lines.push_back(lineSurf);
+    
   }
+  return 1;
 }
 
 int Text::SetTextBlended(string textArg, textSizes_t size, Uint8 r, Uint8 g, Uint8 b) {
@@ -88,29 +149,82 @@ int Text::SetTextBlended(string textArg, textSizes_t size, Uint8 r, Uint8 g, Uin
 int Text::SetTextShaded(string textArg, textSizes_t size, SDL_Color colour, SDL_Color bgColour) {
   _textContents = textArg;
 
-  if(_text != NULL) {
-    SDL_FreeSurface(_text);
+  if(!_lines.empty()) {
+    for(std::list<SDL_Surface*>::iterator it = _lines.begin(); it != _lines.end(); ++it) {
+      SDL_FreeSurface(*it);
+    }
+    _lines.clear();
   }
 
-  if(size == vsmall) {
-    _text = TTF_RenderText_Shaded(vSmallFont, textArg.c_str(), colour, bgColour);
-    return 1;
+  std::list<std::string> lines;
+  std::string line;
+  for(int i = 0; i < (int)textArg.size(); i++) {
+    char c = textArg.at(i);
+    if(c=='\n') {
+      lines.push_back(line);
+      line.clear();
+    } else {
+      line += c;
+    }
   }
-  else if(size == small) {
-    _text = TTF_RenderText_Shaded(smallFont, textArg.c_str(), colour, bgColour);
-    return 1;
+  if (!line.empty()) {
+    lines.push_back(line);
   }
-  else if(size == medium) {
-    _text = TTF_RenderText_Shaded(mediumFont, textArg.c_str(), colour, bgColour);
-    return 1;
-  }
-  else if(size == large) {
-    _text = TTF_RenderText_Shaded(largeFont, textArg.c_str(), colour, bgColour);
-    return 1;
-  } else {
-    _text = TTF_RenderText_Shaded(vLargeFont, textArg.c_str(), colour, bgColour);
-    return 1;
+
+  for(std::list<std::string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+    SDL_Surface* lineSurf;
+    if(size == vsmall) {
+      lineSurf = TTF_RenderText_Shaded(vSmallFont, it->c_str(), colour, bgColour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(vSmallFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    }
+    else if(size == small) {
+      lineSurf = TTF_RenderText_Shaded(smallFont, it->c_str(), colour, bgColour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(smallFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    }
+    else if(size == medium) {
+      lineSurf = TTF_RenderText_Shaded(mediumFont, it->c_str(), colour, bgColour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(mediumFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    }
+    else if(size == large) {
+      lineSurf = TTF_RenderText_Shaded(largeFont, it->c_str(), colour, bgColour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(largeFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    } else {
+      lineSurf = TTF_RenderText_Shaded(vLargeFont, it->c_str(), colour, bgColour);
+      int linePixelWidth;
+      int linePixelHeight;
+      TTF_SizeText(vLargeFont, it->c_str(), &linePixelWidth, &linePixelHeight);
+      if(linePixelWidth > w) {
+        w = linePixelWidth;
+      }
+      h += linePixelHeight + lineSpacing; 
+    }
+    _lines.push_back(lineSurf);
   }
+  return 1;
 }
 
 int Text::SetTextShaded(string textArg, textSizes_t size, Uint8 rF, Uint8 gF, Uint8 bF, Uint8 rB, Uint8 gB, Uint8 bB) {
@@ -120,17 +234,37 @@ int Text::SetTextShaded(string textArg, textSizes_t size, Uint8 rF, Uint8 gF, Ui
 }
 
 void Text::Render(void) {
-  ApplySurface(x, y, _text, screen);
+  int yOffset = 0;
+  for(std::list<SDL_Surface*>::iterator it = _lines.begin(); it != _lines.end(); ++it) {
+    SDL_Surface* lineSurf = *it;
+    ApplySurface(x, y + yOffset, lineSurf, screen);  
+    yOffset += lineSurf->h + lineSpacing; 
+  }
 }
 
 void Text::Render(int xArg, int yArg) {
-  ApplySurface(xArg, yArg, _text, screen);
+  int yOffset = 0;
+  for(std::list<SDL_Surface*>::iterator it = _lines.begin(); it != _lines.end(); ++it) {
+    SDL_Surface* lineSurf = *it;
+    ApplySurface(x + xArg, y + yArg + yOffset, lineSurf, screen);  
+    yOffset += lineSurf->h + lineSpacing; 
+  }
 }
 
 void Text::RenderLiteral(void) {
-  ApplySurfaceLiteral(x, y, _text, screen);
+  int yOffset = 0;
+  for(std::list<SDL_Surface*>::iterator it = _lines.begin(); it != _lines.end(); ++it) {
+    SDL_Surface* lineSurf = *it;
+    ApplySurfaceLiteral(x, y + yOffset, lineSurf, screen);  
+    yOffset += lineSurf->h + lineSpacing; 
+  }
 }
 
 void Text::RenderLiteral(int xArg, int yArg) {
-  ApplySurfaceLiteral(xArg, yArg, _text, screen);
+  int yOffset = 0;
+  for(std::list<SDL_Surface*>::iterator it = _lines.begin(); it != _lines.end(); ++it) {
+    SDL_Surface* lineSurf = *it;
+    ApplySurfaceLiteral(x + xArg, y + yArg + yOffset, lineSurf, screen);  
+    yOffset += lineSurf->h + lineSpacing; 
+  }
 }
diff --git a/src/libUnuk/Text.h b/src/libUnuk/Text.h
index 6a87dfa..fa6c4bb 100644
--- a/src/libUnuk/Text.h
+++ b/src/libUnuk/Text.h
@@ -3,6 +3,7 @@
 #include <SDL/SDL.h>
 #include <SDL/SDL_ttf.h>
 #include <string>
+#include <list>
 
 #include "../Unuk/Globals.h"
 #include "ApplySurface.h"
@@ -20,8 +21,8 @@ public:
   static void LoadFonts(void);
   static void FreeFonts(void);
 
-  int GetWidth(void)          { return _text->w; }
-  int GetHeight(void)         { return _text->h; }
+  int GetWidth(void)          { return w; }
+  int GetHeight(void)         { return h; }
   int GetX(void)              { return x; }
   int GetY(void)              { return y; }
 
@@ -46,7 +47,7 @@ private:
 
   string _textContents;
   SDL_Color _textColour;
-  SDL_Surface* _text;
+  std::list<SDL_Surface*> _lines;
 
   static TTF_Font* vSmallFont;
   static TTF_Font* smallFont;