/*
     PLIB - A Suite of Portable Game Libraries
     Copyright (C) 1998,2002  Steve Baker
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
     License as published by the Free Software Foundation; either
     version 2 of the License, or (at your option) any later version.
 
     This library is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     Library General Public License for more details.
 
     You should have received a copy of the GNU Library General Public
     License along with this library; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
     For further information visit http://plib.sourceforge.net

     $Id: fnt.cpp,v 1.4 2005/06/21 12:24:27 abmann Exp $
*/

#include "fntLocal.h"
#include "../../bomemory/bodummymemory.h"
#include <bodebug.h>

#define DO_LIBUFO 1

BofntFont::BofntFont() {}
BofntFont::~BofntFont() {}

int BofntTexFont::load( const char *fname, GLenum mag, GLenum min )
{
  const char *p ;

  for ( p = & fname [ strlen ( fname ) -1 ] ;
        p != fname && *p != '.' && *p != '/' ; p-- )
  {
    /* Do nothing */ ;
  }

  if ( strcmp ( p, ".txf" ) == 0 ) {
    return loadTXF( fname, mag, min );
  }
  else
  {
    boError() << k_funcinfo << "Unrecognised file format for " << fname << endl;
    return FNT_FALSE;
  }
}



float BofntTexFont::low_putch( sgVec3 curpos, float pointsize,
                               float italic, char c )
{
  unsigned int cc = (unsigned char) c;

  /* Auto case-convert if character is absent from font. */

  if ( ! exists[ cc ] )
  {
    if ( cc >= 'A' && cc <= 'Z' )
    {
      cc = cc - 'A' + 'a' ;
    }
    else if ( cc >= 'a' && cc <= 'z' )
    {
      cc = cc - 'a' + 'A' ;
    }

    if ( cc == ' ' )
    {
      curpos [ 0 ] += pointsize / 2.0f ;
      return pointsize / 2.0f ;
    }
  }

  /*
    We might want to consider making some absent characters from
    others (if they exist): lowercase 'l' could be made into digit '1'
    or letter 'O' into digit '0'...or vice versa. We could also
    make 'b', 'd', 'p' and 'q' by mirror-imaging - this would
    save a little more texture memory in some fonts.
  */

  if ( ! exists[ cc ] )
  {
    return 0.0f ;
  }

  glBegin( GL_TRIANGLE_STRIP ) ;
#if DO_LIBUFO
    // AB: libufo uses a different projection (origin in top-left, not
    // bottom-right as with usual OpenGL)
    const float bottom = curpos[1] + pointsize - v_bot[cc] * pointsize;
    const float top    = curpos[1] + pointsize -  v_top[cc] * pointsize;
#else
    // original plib code:
    const float bottom = curpos[1] + v_bot[cc] * pointsize;
    const float top    = curpos[1] + v_top[cc] * pointsize;
#endif
    const float left_bottom  = curpos[0] + v_left[cc]             * pointsize;
    const float right_bottom = curpos[0] + v_right[cc]            * pointsize;
    const float left_top     = curpos[0] + (italic + v_left[cc])  * pointsize;
    const float right_top    = curpos[0] + (italic + v_right[cc]) * pointsize;
    glTexCoord2f( t_left[cc], t_bot[cc] ) ;
    glVertex3f(left_bottom,
                   bottom,
                   curpos[2] );

    glTexCoord2f( t_left[cc], t_top[cc] ) ;
    glVertex3f(left_top,
                   top,
                   curpos[2] );

    glTexCoord2f( t_right[cc], t_bot[cc] ) ;
    glVertex3f(right_bottom,
                   bottom,
                   curpos[2] );

    glTexCoord2f( t_right[cc], t_top[cc] ) ;
    glVertex3f(right_top,
                   top,
                   curpos[2] );
  glEnd();

  float ww = ( gap + ( fixed_pitch ? width : widths[cc] ) ) * pointsize;
  curpos[0] += ww;
  return ww;
}


#include <math.h>
void BofntTexFont::setGlyph( char c, float wid,
        float tex_left, float tex_right,
        float tex_bot , float tex_top  ,
        float vtx_left, float vtx_right,
        float vtx_bot , float vtx_top  )
{
  unsigned int cc = (unsigned char) c ;

  exists[cc] = FNT_TRUE ;

  widths[cc] = wid;
  if (wid > widestChar)
  {
    widestChar = wid;
  }

  t_left[cc] = tex_left ; t_right[cc] = tex_right ;
  t_bot [cc] = tex_bot  ; t_top  [cc] = tex_top   ;

  v_left[cc] = vtx_left ; v_right[cc] = vtx_right ;
  v_bot [cc] = vtx_bot  ; v_top  [cc] = vtx_top   ;
}


int BofntTexFont::getGlyph( char c, float* wid,
        float *tex_left, float *tex_right,
        float *tex_bot , float *tex_top  ,
        float *vtx_left, float *vtx_right,
        float *vtx_bot , float *vtx_top  )
{
  unsigned int cc = (unsigned char) c;

  if ( ! exists[cc] ) { return FNT_FALSE; }

  if ( wid       != NULL ) { *wid       = widths [cc]; }

  if ( tex_left  != NULL ) { *tex_left  = t_left [cc]; }
  if ( tex_right != NULL ) { *tex_right = t_right[cc]; }
  if ( tex_bot   != NULL ) { *tex_bot   = t_bot  [cc]; }
  if ( tex_top   != NULL ) { *tex_top   = t_top  [cc]; }

  if ( vtx_left  != NULL ) { *vtx_left  = v_left [cc]; }
  if ( vtx_right != NULL ) { *vtx_right = v_right[cc]; }
  if ( vtx_bot   != NULL ) { *vtx_bot   = v_bot  [cc]; }
  if ( vtx_top   != NULL ) { *vtx_top   = v_top  [cc]; }

  return FNT_TRUE ;
}


void BofntTexFont::getBBox( const char *s,
                           float pointsize, float italic,
                           float *left, float *right,
                           float *bot , float *top  )
{
  float h_pos = 0.0f;
  float v_pos = 0.0f;
  float l, r, b, t;

  l = r = b = t = 0.0f;

  while ( *s != '\0' )
  {
    if ( *s == '\n' )
    {
      h_pos = 0.0f;
      v_pos -= 1.333f;
      s++;
      continue ;
    }

    unsigned int cc = (unsigned char) *(s++) ;

    if ( ! exists [ cc ] )
    {
      if ( cc >= 'A' && cc <= 'Z' )
      {
        cc = cc - 'A' + 'a';
      }
      else if ( cc >= 'a' && cc <= 'z' )
      {
        cc = cc - 'a' + 'A';
      }

      if ( cc == ' ' )
      {
        r += 0.5f;
        h_pos += 0.5f;

        continue ;
      }
    }

    if ( ! exists [ cc ] )
      continue ;

    if ( italic >= 0 )
    {
      if ( l >       h_pos + v_left [cc]        ) l =       h_pos + v_left [cc];
      if ( r < gap + h_pos + v_right[cc]+italic ) r = gap + h_pos + v_right[cc] + italic;
    }
    else
    {
      if ( l >       h_pos + v_left [cc]+italic ) l =       h_pos + v_left [cc] + italic;
      if ( r < gap + h_pos + v_right[cc] )        r = gap + h_pos + v_right[cc];
    }


    if ( b > v_pos + v_bot [cc] ) b = v_pos + v_bot [cc];
    if ( t < v_pos + v_top [cc] ) t = v_pos + v_top [cc];

    h_pos += gap + ( fixed_pitch ? width : widths[cc] );
  }

  if ( left  != NULL ) { *left  = l * pointsize; }
  if ( right != NULL ) { *right = r * pointsize; }
  if ( top   != NULL ) { *top   = t * pointsize; }
  if ( bot   != NULL ) { *bot   = b * pointsize; }
}


void BofntTexFont::puts( sgVec3 curpos, float pointsize, float italic, const char *s )
{
  SGfloat origx = curpos[0];

  if ( ! bound )
  {
    bind_texture();
  }

  while ( *s != '\0' )
  {
    if (*s == '\n')
    {
      curpos[0] = origx;
      curpos[1] -= pointsize * 1.333f;
    }
    else
    {
      low_putch( curpos, pointsize, italic, *s );
    }

    s++;
  }
}

/*
 * vim: et sw=2
 */
