Index: trunk/src/lib/graphics/text_engine/text.cc
===================================================================
--- trunk/src/proto/proto_class.cc	(revision 5070)
+++ trunk/src/lib/graphics/text_engine/text.cc	(revision 5343)
@@ -10,41 +10,394 @@
 
    ### File Specific:
-   main-programmer: ...
+   main-programmer: Benjamin Grauer
    co-programmer: ...
 */
 
-//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
-
-#include "proto_class.h"
+#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_FONT
+
+#include "text.h"
+#include "font.h"
+
+#include "graphics_engine.h"
+#include "resource_manager.h"
+#include "class_list.h"
+#include "debug.h"
+#include "p_node.h"
 
 using namespace std;
 
-
-/**
- * standard constructor
- * @todo this constructor is not jet implemented - do it
-*/
-ProtoClass::ProtoClass ()
-{
-   this->setClassID(CL_PROTO_ID, "ProtoClass");
-
-   /* If you make a new class, what is most probably the case when you write this file
-      don't forget to:
-       1. Add the new file new_class.cc to the ./src/Makefile.am
-       2. Add the class identifier to ./src/class_id.h eg. CL_NEW_CLASS
-
-      Advanced Topics:
-      - if you want to let your object be managed via the ObjectManager make sure to read
-        the object_manager.h header comments. You will use this most certanly only if you
-        make many objects of your class, like a weapon bullet.
-   */
-}
-
-
-/**
- * standard deconstructor
-*/
-ProtoClass::~ProtoClass ()
-{
-  // delete what has to be deleted here
-}
+/**
+ *  creates a new Text Element
+ * @param fontFile the Font to render this text in
+ * @param type The renderType to display this font in
+ */
+Text::Text(const char* fontFile, unsigned int fontSize, TEXT_RENDER_TYPE type)
+{
+  this->init();
+
+  if (fontFile != NULL)
+    this->setFont(fontFile, fontSize);
+  this->setType(type);
+}
+
+/**
+ *  creates a new Text Element
+ * @param font the Font to render this text in
+ * @param type The renderType to display this font in
+ *
+ * this constructor is private, because the user should initialize
+ * a text with the TextEngine.
+ */
+Text::Text(Font* font, TEXT_RENDER_TYPE type)
+{
+  this->init();
+
+  this->font = font;
+  this->setType(type);
+}
+
+/**
+ *  deletes a Text out of memory
+ *
+ * This also ereases the text from the textList of the TextEngine
+ */
+Text::~Text()
+{
+  if (this->font != NULL)
+    ResourceManager::getInstance()->unload(this->font);
+
+  if (this->text)
+    delete[] this->text;
+}
+
+void Text::init()
+{
+  this->setClassID(CL_TEXT, "Text");
+
+  // initialize this Text
+  this->font = NULL;
+  this->text = NULL;
+  this->externText = NULL;
+  this->setAlignment(TEXT_DEFAULT_ALIGNMENT);
+  this->texture = 0;
+  this->blending = TEXT_DEFAULT_BLENDING;
+  this->color = TEXT_DEFAULT_COLOR;
+  this->setType(TEXT_RENDER_DYNAMIC);
+
+  this->setText(NULL);
+}
+
+/**
+ * sets the Font of this Text to font
+ * @param font the Font (normaly from the ResourceManager) to allocate to this Text
+ */
+void Text::setFont(Font* font)
+{
+  if (this->font != NULL)
+    ResourceManager::getInstance()->unload(this->font);
+  this->font = font;
+}
+
+/**
+ * sets the Font of this Text to font from fontFile
+ * @param fontFile the File to load the Font from.
+ * @param fontSize the Size of the Font
+ */
+void Text::setFont(const char* fontFile, unsigned int fontSize)
+{
+  Font* tmpFont;
+  Text* newText;
+  Vector tmpVec;
+
+  tmpFont = (Font*)ResourceManager::getInstance()->load(fontFile, TTF, RP_GAME, &fontSize);
+  if (tmpFont == NULL)
+  {
+    PRINTF(2)("Font %s could not be loaded, probably file not found\n", fontFile);
+    this->setFont(NULL);
+  }
+  else
+    this->setFont(tmpFont);
+}
+
+/**
+ *  sets the Type of this Text
+ * @param type the type to set.
+ */
+void Text::setType(TEXT_RENDER_TYPE type)
+{
+  if (this->font != NULL && this->font->font)
+    this->type = type;
+  else
+    this->type = TEXT_RENDER_DYNAMIC;
+}
+
+/**
+ *  Sets a new Text to the font
+ * @param text the new text to set
+ */
+void Text::setText(const char* text, bool isExtern)
+{
+  if (isExtern)
+  {
+    this->externText = text;
+
+    if (unlikely(this->text != NULL))
+    {
+      delete[] this->text;
+      this->text = NULL;
+    }
+  }
+  else
+  {
+    this->externText = NULL;
+    if (this->text)
+      delete[] this->text;
+    if (text != NULL)
+    {
+      this->text = new char[strlen(text)+1];
+      strcpy(this->text, text);
+    }
+    else
+      this->text = NULL;
+  }
+
+  // setting up the Text-Width if DYNAMIC
+  if (this->type & TEXT_RENDER_DYNAMIC && this->getAlignment() != TEXT_ALIGN_LEFT && this->font != NULL)
+  {
+    Glyph** glyphArray = this->font->getGlyphArray();
+
+    int width = 0;
+    const char* tmpText = this->externText;
+    if (this->externText == NULL)
+      tmpText = this->text;
+    if (tmpText != NULL)
+    {
+      while (*tmpText != '\0')
+      {
+        if(glyphArray[*tmpText])
+        {
+          width += glyphArray[*tmpText]->width;
+        }
+        tmpText++;
+      }
+      this->width = width;
+    }
+  }
+}
+
+/**
+ *  creates a texture out of the given parameters
+
+   this has to be called every time by the user, to if changes were made.
+   this is only for TEXT_STATIC-mode
+ */
+void Text::createTexture()
+{
+  SDL_Surface* tmpSurf;
+  if (this->texture)
+    glDeleteTextures(1, &this->texture);
+  if (likely(this->font != NULL))
+  {
+    SDL_Color theColor = { (int)(this->color.x*255), (int)(this->color.y*255), (int)(this->color.z*255) };
+    tmpSurf = TTF_RenderText_Blended(this->font->font,
+                                     this->text,
+                                     theColor);
+  }
+  if (tmpSurf)
+    this->texture = loadTexture(tmpSurf, &this->texCoord);
+
+  this->width = tmpSurf->w;
+  this->height = tmpSurf->h;
+  SDL_FreeSurface(tmpSurf);
+}
+
+/**
+ *  draws the Text
+ */
+void Text::draw() const
+{
+  glPushMatrix();
+  // transform for alignment.
+  if (this->getAlignment() == TEXT_ALIGN_RIGHT)
+    glTranslatef(-this->width, 0, 0);
+  else if (this->getAlignment() == TEXT_ALIGN_CENTER || this->getAlignment() == TEXT_ALIGN_SCREEN_CENTER)
+    glTranslatef(-this->width/2, 0, 0);
+
+  // drawing this Text.
+  // setting the Blending effects
+  glColor4f(this->color.x, this->color.y, this->color.z, this->blending);
+  glEnable(GL_BLEND);
+  glEnable(GL_TEXTURE_2D);
+  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_MODULATE );
+
+  if(likely(type & TEXT_RENDER_DYNAMIC ))
+  {
+    Glyph** glyphArray;
+    if (likely (this->font != NULL))
+    {
+      glyphArray = this->font->getGlyphArray();
+      glBindTexture(GL_TEXTURE_2D, font->getFastTextureID());
+    }
+    else
+    {
+      if (unlikely(Font::getDefaultFont() == NULL))
+        Font::initDefaultFont();
+      glyphArray = Font::getDefaultFont()->getGlyphArray();
+      glBindTexture(GL_TEXTURE_2D, Font::getDefaultFont()->getFastTextureID());
+    }
+    glTranslatef(getAbsCoor2D().x, getAbsCoor2D().y, 0);
+//      glRotatef(this->getAbsDir2D(), 0,0,1);
+    const char* tmpText = this->externText;
+    if (this->externText == NULL)
+      tmpText = this->text;
+    if (likely(tmpText != NULL))
+    {
+      while (likely(*tmpText != '\0'))
+      {
+        if(likely(glyphArray[*tmpText] != NULL))
+        {
+          glCallList(glyphArray[*tmpText]->displayList);
+          glTranslatef(glyphArray[*tmpText]->width, 0, 0);
+        }
+        tmpText++;
+      }
+    }
+  }
+  else //(if type & TEXT_RENDER_STATIC)
+  {
+    glBindTexture(GL_TEXTURE_2D, this->texture);
+    glBegin(GL_QUADS);
+
+    glTexCoord2f(this->texCoord.minU, this->texCoord.minV);
+    glVertex2f(this->getAbsCoor2D().x,   this->getAbsCoor2D().y  );
+
+    glTexCoord2f(this->texCoord.maxU, this->texCoord.minV);
+    glVertex2f(this->getAbsCoor2D().x + this->width, this->getAbsCoor2D().y  );
+
+    glTexCoord2f(this->texCoord.maxU, this->texCoord.maxV);
+    glVertex2f(this->getAbsCoor2D().x + this->width, getAbsCoor2D().y + this->height);
+
+    glTexCoord2f(this->texCoord.minU, this->texCoord.maxV);
+    glVertex2f(getAbsCoor2D().x, getAbsCoor2D().y + this->height);
+
+    glEnd();
+
+  }
+  glPopMatrix();
+}
+
+/**
+ *  prints out some nice debug information about this text
+ */
+void Text::debug() const
+{
+  if (this->externText == NULL)
+    PRINT(0)("=== TEXT: %s ===\n", this->text);
+  else
+    PRINT(0)("=== TEXT: %s ===\n", this->externText);
+
+  if (this->getBindNode())
+    PRINT(0)("is bind to %s; ref=%p\n", this->getBindNode()->getName(), this->getBindNode());
+  PRINT(0)("Color: %0.2f %0.2f %0.2f\n", this->color.x, this->color.y, this->color.z);
+}
+
+
+////////////
+/// UTIL ///
+////////////
+/**
+ *  Loads a Font from an SDL_surface into a texture.
+ * @param surface The surface to make the texture of
+ * @param texCoord The texture coordinates of the 4 corners of the texture
+ * @returns the ID of the texture
+ */
+GLuint Text::loadTexture(SDL_Surface *surface, TexCoord* texCoord)
+{
+  GLuint texture;
+  int w, h;
+  SDL_Surface *image;
+  SDL_Rect area;
+  Uint32 saved_flags;
+  Uint8  saved_alpha;
+
+  /* Use the surface width and height expanded to powers of 2 */
+  w = powerOfTwo(surface->w);
+  h = powerOfTwo(surface->h);
+  if (texCoord != NULL)
+  {
+    texCoord->minU = 0.0f;
+    texCoord->minV = 0.0f;
+    texCoord->maxU = (GLfloat)surface->w / w;
+    texCoord->maxV = (GLfloat)surface->h / h;
+  }
+  image = SDL_CreateRGBSurface(SDL_SWSURFACE,
+                               w, h,
+                               32,
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
+                               0x000000FF,
+                               0x0000FF00,
+                               0x00FF0000,
+                               0xFF000000
+#else
+                                   0xFF000000,
+                               0x00FF0000,
+                               0x0000FF00,
+                               0x000000FF
+#endif
+                              );
+  if ( image == NULL ) {
+    return 0;
+  }
+
+  /* Save the alpha blending attributes */
+  saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
+  saved_alpha = surface->format->alpha;
+  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
+    SDL_SetAlpha(surface, 0, 0);
+  }
+
+  /* Copy the surface into the GL texture image */
+  area.x = 0;
+  area.y = 0;
+  area.w = surface->w;
+  area.h = surface->h;
+  SDL_BlitSurface(surface, &area, image, &area);
+
+  /* Restore the alpha blending attributes */
+  if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
+    SDL_SetAlpha(surface, saved_flags, saved_alpha);
+  }
+
+  /* Create an OpenGL texture for the image */
+  glGenTextures(1, &texture);
+  glBindTexture(GL_TEXTURE_2D, texture);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexImage2D(GL_TEXTURE_2D,
+               0,
+               GL_RGBA,
+               w, h,
+               0,
+               GL_RGBA,
+               GL_UNSIGNED_BYTE,
+               image->pixels);
+  SDL_FreeSurface(image); /* No longer needed the data */
+
+  return texture;
+}
+
+/**
+ *  Quick utility function for texture creation
+ * @param input an integer
+ * @returns the next bigger 2^n-integer than input
+ */
+int Text::powerOfTwo(int input)
+{
+  int value = 1;
+
+  while ( value < input )
+    value <<= 1;
+  return value;
+}
