/*********************************************************************
 *
 *         EZWGL, the EZ Widget and Graphics Library
 *
 *             Copyright (C) 1996, 1997  Maorong Zou
 *  
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/
/*
 *  June 1996.  Beta Release.
 *  Sept 1996.  Release Version 1.0
 *  Dec 1996.  Release Version 1.1 Beta
 *  April 1997.  Release Version 1.2
 *  November 1997.  Release Version 1.3
 */
/**************************************************************
 *
 *  Render strings.
 */
#define _EZ_STRING_C_

#include <stdio.h>
#include "EZ_Widget.h"
#include "EZ_VectFont.h"
#include "EZ_Render.h"

/**************************************************************
 *
 *  Functions implemented in this file:
 */

void         EZ_SetVectorFont MY_ANSIARGS((int fid));
void         EZ_SetBitmapFont  MY_ANSIARGS((char *fname));
void         EZ_CMove2f  MY_ANSIARGS((float x, float y)); 
void         EZ_CMove3f MY_ANSIARGS((float x, float y, float z)); 
void         EZ_CMove3v MY_ANSIARGS((float *xyz)); 
void         EZ_CMoveScreen2f  MY_ANSIARGS((float x, float y)); 
void         EZ_CMoveScreen3f MY_ANSIARGS((float x, float y, float z)); 
void         EZ_CMoveScreen3fv MY_ANSIARGS((float *xyz)); 
void         EZ_DrawString MY_ANSIARGS((int font, char *str)); 

/**************************************************************/

#define DRAW_STRING_WORLD  0
#define DRAW_STRING_SCREEN 1

static float  EZ_CurTxtPos[4];
static int    EZ_CurTxtPosScrn[3];
static int    draw_string_type = DRAW_STRING_WORLD;

/************************************************************
 *
 *  Local functions
 */
static void   EZ_DrawStringVFont MY_ANSIARGS((char *str));
static void   EZ_DrawStringBFont MY_ANSIARGS((char *str));
static void   EZ_DrawStringVFont_Work MY_ANSIARGS((char *str, int x, int y, int z));
static void   EZ_DrawStringBFont_Work MY_ANSIARGS((char *str, int x, int y, int z));

/**************************************************************
 *
 *  Render string
 */
void EZ_DrawString(font,str)
     int font;
     char *str;
{
  if(EZ_InCompilingMode != 0)
    {
      char *tmp;
      int  length;
      int  size = (64*sizeof(EZ_Token)/sizeof(char)) - 4;
      EZ_Token *t = AllocateNTokens(66);
      t->i = TOKEN_DRAW_STRING;
      t++;
      t->i = font;
      t++;  
      t->ptr = t+1;
      tmp = (char *)(t->ptr);
      length = strlen(str);
      if(length > size) length = size;
      (void) strncpy(tmp,str,length);
      tmp[length] = '\0';
    }
  if(EZ_InExecutionMode != 0)
    {
      if(font == EZ_VECTOR_FONT)
	EZ_DrawStringVFont(str);
      else if(font == EZ_BITMAP_FONT)
	EZ_DrawStringBFont(str);
    }
}

/**************************************************************
 *
 * set vector font
 */
void EZ_SetVectorFont(font)
     int font;
{
  if(font == 0)   EZ_CurrentFont = EZ_SMALL_FONT;
  else  EZ_CurrentFont = EZ_LARGE_FONT;
}
  
/**************************************************************
 *
 * set the current text position, in modeling space.
 */
void EZ_CMove2f(x,y) 
     float x,y;
{
  EZ_CMove3f(x,y,0.0);
}

void EZ_CMove3f(x,y,z)
     float x,y,z;
{
  if(EZ_InCompilingMode != 0)
    {
      EZ_Token *t = AllocateNTokens(4);
      t->i = TOKEN_CMOVE;
      t[1].f = x;
      t[2].f = y;
      t[3].f = z;
    }
  if(EZ_InExecutionMode != 0)
    {
      EZ_CurTxtPos[0] = x;
      EZ_CurTxtPos[1] = y;
      EZ_CurTxtPos[2] = z;
      draw_string_type = DRAW_STRING_WORLD;
    }
}

void EZ_CMove3fv(x)
     float *x;
{
  EZ_CMove3f(x[0],x[1],x[2]);
}

/**************************************************************
 *
 * set the current text position, in normalized clipping space.
 * The normalized screen is [-1,1]x[-1,1]x[-1,1].
 */
void EZ_CMoveScreen3fv(x)
     float *x;
{
  EZ_CMoveScreen3f(x[0],x[1],x[2]);
}
void EZ_CMoveScreen2f(x,y)
     float x,y;
{
  EZ_CMoveScreen3f(x,y,0.0);
}

void EZ_CMoveScreen3f(x,y,z)
     float x,y,z;
{
  if(EZ_InCompilingMode != 0)
    {
      EZ_Token *t = AllocateNTokens(4);
      t->i = TOKEN_CMOVE_SCREEN;
      t[1].f = x;
      t[2].f = y;
      t[3].f = z;
    }
  if(EZ_InExecutionMode != 0)
    {
      float tmpf[4];
  
      tmpf[0] = (x <-1.0 ? -1.0: x > 1.0? 1.0: x);
      tmpf[1] = (y <-1.0 ? -1.0: y > 1.0? 1.0: y);
      tmpf[2] = (z <-1.0 ? -1.0: z > 1.0? 1.0: z);
      tmpf[3] = 1.0;

      TRANSFORM_2_SCREEN(tmpf, EZ_CurTxtPosScrn[0],EZ_CurTxtPosScrn[1],EZ_CurTxtPosScrn[2]);
      draw_string_type = DRAW_STRING_SCREEN;
    }
}

/**************************************************************
 *
 *  Render string using vector font.
 */
static void EZ_DrawStringVFont(str)
     char  *str;
{
  if(draw_string_type == DRAW_STRING_WORLD)
    {
      float           hcoor[4];
      int             xx,yy,zz;

      /*
       * first, transform the current text position to
       * screen space.
       */
      TRANSFORM_VERTEX(hcoor,EZ_CurTxtPos);
      TRANSFORM_2_SCREEN(hcoor, xx, yy, zz);

      EZ_DrawStringVFont_Work(str, xx,yy, zz);
    }
  else
    EZ_DrawStringVFont_Work(str, EZ_CurTxtPosScrn[0],EZ_CurTxtPosScrn[1],EZ_CurTxtPosScrn[2]);
}

/**************************************************************
 *
 *  Render string. Do Text cliping.
 */

static void EZ_DrawStringVFont_Work(str, sx,sy,sz)
     char  *str;
     int   sx,sy, sz;
{
  register int    i, j, k;
  int             ox, oy, nx;
  int             length, chwidth, chheight;
  char            *chbgn, *chend;
  int             WindowMinCoorY = 0, WindowMinCoorX = 0;
  int             WindowMaxCoorX = EZ_WindowWidth - 1;
  int             WindowMaxCoorY = EZ_WindowHeight -1;
  
  chwidth =  EZ_TextWidth  << EZ_CurrentFont;
  chheight = EZ_TextHeight << EZ_CurrentFont;

  oy = sy;

  /*--------------------------------
   * clip in the vertical direction
   *-------------------------------*/
  if(oy > WindowMaxCoorY  || oy < WindowMinCoorY) return;

  if(oy <= WindowMinCoorY + chheight)
    oy  += (chheight + 1);

  if(oy > WindowMaxCoorY) return;

  /*----------------------------------
   * clip in the horizontal direction
   *---------------------------------*/
  length = strlen(str);
  chbgn = str; 

  ox = sx;
  if((ox >= WindowMaxCoorX)  ||
     (ox + length * chwidth <= WindowMinCoorX))  return;
  
  while(ox < WindowMinCoorX && length > 0)
    {
      chbgn++; 
      ox += chwidth;
      length--;
    }
  if(length == 0) return;
  /*----------------------------------
   * select the substring that is 
   * inside the viewport
   *---------------------------------*/  
  nx = ox + length * chwidth;
  while(nx > WindowMaxCoorX && length >= 0)
    {
      nx  -= chwidth;
      length--;
    }
  if(length == 0) return;
  chend = chbgn + length;
  
  /*----------------------
   * now render the text
   *---------------------*/
  {
    int (*npos)[3] = EZ_VBuf.screen;
    int (*rgba)[4] = EZ_VBuf.rgbaF;

    EZ_VBuf.rgba = EZ_VBuf.rgbaF;
    rgba[0][0] = EZ_CurrentColorI[0];
    rgba[0][1] = EZ_CurrentColorI[1];
    rgba[0][2] = EZ_CurrentColorI[2];

    rgba[1][0] = EZ_CurrentColorI[0];
    rgba[1][1] = EZ_CurrentColorI[1];
    rgba[1][2] = EZ_CurrentColorI[2];

    npos[0][0] = ox;
    npos[0][1] = oy;
    npos[0][2] = npos[1][2] = sz;
    
    
    for(str = chbgn; str != chend; str++)
      {
	k = (int) (*str);
	if(EZ_VectFontTable[k][0][0]) 
	  {
	    i = 0;
	    while( (j = EZ_VectFontTable[k][i][0]) )
	      {
		switch (j) 
		  {
		  case 3:
		    npos[0][0] += 
		      (EZ_CurrentFont +1)* EZ_VectFontTable[k][i][1];
		    npos[0][1] -= 
		      (EZ_CurrentFont +1)* EZ_VectFontTable[k][i][2];
		    break;
		  case 2:
		    npos[1][0] = npos[0][0] +
		      (EZ_CurrentFont +1)* EZ_VectFontTable[k][i][1];
		    npos[1][1] = npos[0][1] -
		      (EZ_CurrentFont +1)* EZ_VectFontTable[k][i][2];
		    EZ_CURRENT_LINE_FUNC(0, 1);
		    npos[0][0] = npos[1][0]; 
		    npos[0][1] = npos[1][1];
		    break;
		  default:
		    break;
		  }
		i++;
	      }
	  }
      }
  }
}

/********************************************************************
 *
 *  Set the current bitmap font.
 */
void EZ_SetBitmapFont(name)
     char *name;
{
  EZ_BitmapFont = EZ_GetFontFromName(name);
  XSetFont(EZ_Display,EZ_MainGC,EZ_BitmapFont->fid);
}
/********************************************************************
 *
 * Render string using bitmap font
 */
static void  EZ_DrawStringBFont(str)
     char *str;
{
  if(EZ_DoubleBufferSet == EZ_XIMAGE && EZ_FrontBufferSet == 0)
    EZ_DrawStringVFont(str);
  else
    {
      unsigned long pixel_value;

      if(EZ_ColorMode == EZ_CMAP_MODE)
	{
	  int ir = EZ_CurrentColorI[0] >> COLOR_SHIFT_BITS;
	  pixel_value = EZ_ColorArray[ir];
	}
      else
	{
	  int r = EZ_CurrentColorI[0] >> COLOR_SHIFT_BITS;
	  int g = EZ_CurrentColorI[1] >> COLOR_SHIFT_BITS;
	  int b = EZ_CurrentColorI[2] >> COLOR_SHIFT_BITS;
	  if(EZ_Depth <= 8)
	    {
	      EZ_DitherRGB(pixel_value,4,5, r,g,b);
	    }
	  else
	    {
	      pixel_value = RGB2PixelLookUp(r,g,b);
	    }
	}
      XSetForeground(EZ_Display,EZ_MainGC,pixel_value);

      if(draw_string_type == DRAW_STRING_WORLD)
	{
	  float           hcoor[4], *fptr;
	  int             xxx,yyy,zzz;
	  /*
	   * first, transform the current text position to
	   * screen space.
	   */
	  fptr =  EZ_CurTxtPos;
	  TRANSFORM_VERTEX(hcoor,fptr);
	  TRANSFORM_2_SCREEN(hcoor, xxx,yyy,zzz);

	  EZ_DrawStringBFont_Work(str, xxx,yyy,zzz);
	}
      else
	EZ_DrawStringBFont_Work(str, EZ_CurTxtPosScrn[0],EZ_CurTxtPosScrn[1],EZ_CurTxtPosScrn[2]);
    }
}


static void EZ_DrawStringBFont_Work(str, sx,sy,sz)
     char  *str;
     int   sx,sy,sz;
{
  int  descent,ascent, top, bottom, i;  
  int  nx, ox, oy, length,tlength;
  int  WindowMinCoorY = 1, WindowMinCoorX = 1;
  int  WindowMaxCoorX = EZ_WindowWidth - 1;
  int  WindowMaxCoorY = EZ_WindowHeight -1;
  char *chbgn;

  oy = sy;
  descent = EZ_BitmapFont->descent;
  bottom = oy + descent;
  ascent  = EZ_BitmapFont->ascent;
  top = oy - ascent;
  
  /*--------------------------------
   * clip in the vertical direction
   *-------------------------------*/
  if(bottom >= WindowMaxCoorY  || top <= WindowMinCoorY) return;

  /*----------------------------------
   * clip in the horizontal direction
   *---------------------------------*/
  length = strlen(str);
  tlength = XTextWidth(EZ_BitmapFont,str, length);
  
  ox = sx;
  if((ox >= WindowMaxCoorX) || (ox + tlength  <= WindowMinCoorX))  return;

  /*--------------------------------------
   * figure out the visible piece of str
   *-------------------------------------*/
  chbgn = str; 
  
  i = 1;
  while(ox <= WindowMinCoorX && length > 0)
    {
      chbgn++; 
      ox += XTextWidth(EZ_BitmapFont,str, i);
      i++;
      length--;
    }
  if(length == 0) return;

  str = chbgn;
  tlength = XTextWidth(EZ_BitmapFont,str,length);
  nx = ox + tlength;
  
  while(nx > WindowMaxCoorX && length > 0)
    {
      length--;
      if(length > 0)
	nx = ox + XTextWidth(EZ_BitmapFont,str,length);
    }
  if(length <= 0) return;

  XDrawString(EZ_Display,EZ_Drawable,EZ_MainGC, ox, oy, str, length);
}
/********************************************************************/
#undef _EZ_STRING_C_
