/*
 * Copyright (C) 1997-2009, R3vis Corporation.
 *
 * 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, or visit http://www.gnu.org/copyleft/lgpl.html.
 *
 * Original Contributor:
 *   Wes Bethel, R3vis Corporation, Marin County, California
 *   http://www.r3vis.com/
 * Additional Contributor(s):
 *
 * The OpenRM project is located at http://openrm.sourceforge.net/.
 */
/*
 * $Id: rmtext.c,v 1.5 2005/02/19 16:40:20 wes Exp $
 * Version: $Name: v180-alpha-02 $
 * $Revision: 1.5 $
 * $Log: rmtext.c,v $
 * Revision 1.5  2005/02/19 16:40:20  wes
 * Distro sync and consolidation.
 * Repairs to fix memory leak associated with repeated calls to rmPipeNew,
 * rmPipeMakeCurrent, rmPipeClose.
 *
 * Revision 1.4  2005/01/23 17:00:22  wes
 * Copyright updated to 2005.
 *
 * Revision 1.3  2004/01/16 16:48:35  wes
 * Updated copyright line for 2004.
 *
 * Revision 1.2  2003/02/02 02:07:16  wes
 * Updated copyright to 2003.
 *
 * Revision 1.1.1.1  2003/01/28 02:15:23  wes
 * Manual rebuild of rm150 repository.
 *
 * Revision 1.11  2003/01/16 22:21:17  wes
 * Updated all source files to reflect new organization of header files:
 * all header files formerly located in include/rmaux, include/rmi, include/rmv
 * are now located in include/rm.
 *
 * Revision 1.10  2002/04/30 19:33:49  wes
 * Updated copyright dates.
 *
 * Revision 1.9  2001/10/15 00:12:59  wes
 * Added a routine to copy all salient fields from one RMtextProps
 * object to another.
 *
 * Revision 1.8  2001/07/15 16:20:14  wes
 * Fixed bug associated with font emboldening and italicization.
 *
 * Revision 1.7  2001/03/31 17:12:39  wes
 * v1.4.0-alpha-2 checkin.
 *
 * Revision 1.6  2000/12/03 22:35:38  wes
 * Mods for thread safety.
 *
 * Revision 1.5  2000/10/03 11:40:28  wes
 * Contributions from jdb - prototype cleanups.
 *
 * Revision 1.4  2000/08/23 23:30:29  wes
 * Changed embolden and italicization parms from ints to RMenums
 * on rmTextPropsGetAttribs.
 *
 * Revision 1.3  2000/05/17 14:25:13  wes
 * Fixed compile warnings on rmTextPropsSet/GetAttribs().
 *
 * Revision 1.2  2000/04/20 16:29:47  wes
 * Documentation additions/enhancements, some code rearragement.
 *
 * Revision 1.1.1.1  2000/02/28 21:29:40  wes
 * OpenRM 1.2 Checkin
 *
 * Revision 1.1.1.1  2000/02/28 17:18:48  wes
 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
 *
 */

#include <rm/rm.h>
#include "rmprivat.h"

/*
 * ----------------------------------------------------
 * @Name rmTextPropsSetAttribs
 @pstart
 RMenum rmTextPropsSetAttribs (RMtextProps *toModify,
		               int fontEnum,
			       int sizeEnum,
			       RMenum boldEnum,
			       RMenum italicEnum,
			       RMenum hJustifyEnum,
			       RMenum vJustifyEnum)

 @pend

 @astart
 RMtextProps *toModify - a handle to an RMtextProps object (modified).

 int fontEnum - an integer value that specifies a font. Must be one of
    RM_FONT_SERIF, RM_FONT_SANS, RM_FONT_MONO, RM_FONT_SYMBOL or
    RM_FONT_DINGBATS (input). 

 int sizeEnum - an integer value that specifies a typeface size. Must
    be one of RM_FONT_XXS, RM_FONT_XS, RM_FONT_S, RM_FONT_M,
    RM_FONT_L, RM_FONT_XL or RM_FONT_XXL (input).

 RMenum boldEnum - an integer value that indicates if an emboldened
    typeface should be used. Must be either RM_TRUE or RM_FALSE
    (input).

 RMenum italicEnum - an integer value that specifies if an italicized
    typeface should be used. Must be either RM_TRUE or RM_FALSE
    (input).

 RMenum hJustifyEnum - an RMenum value that dicates a horizontal
    justification policy for text. Must be one of RM_LEFT, RM_CENTER
    or RM_RIGHT (input).

 RMenum vJustifyEnum - an RMenum value that dictates a vertical
    justification policy for text. Must be one of RM_BOTTOM, RM_CENTER
    or RM_TOP (input).
 @aend

 @dstart

 Typeface properties in RM are specified by assiging an RMtextProps
 object to a scene graph node as a scene parameter. All descendent
 nodes that contain text will be rendered according to the
 specifications contained in the RMtextProps object. The intent of
 this object is to provide control over text rendering across all
 supported platforms with a single set of parameters.

 This routine modifies an RMtextProps object to reflect the
 caller-supplied parameters. RM_CHILL is returned upon success, or
 RM_WHACKED upon failure.

 Use rmTextPropsNew to create a new RMtextProps object, or
 rmTextPropsDelete to delete an old one that is no longer needed.

 fontEnum specifies a typeface family. On the X11 platform,
 RM_FONT_SERIF corresponds to "adobe-times," RM_FONT_SANS to
 "adobe-helvetica," RM_FONT_MONO to "adobe-courier," RM_FONT_SYMBOL to
 "adobe-symbol" and RM_FONT_DINGBATS to "-*-*-zapfdingbats". On the
 Win32 platform, the values of "times", "helvetica", "courier",
 "symbol" and "zapfdingbats" are used.

 sizeEnum specifies a particular point size for the face. RM_FONT_XXS,
 RM_FONT_XS, RM_FONT_S, RM_FONT_M, RM_FONT_L, RM_FONT_XL and
 RM_FONT_XXL correspond to 8, 10, 12, 14, 18, 24 and 34 points,
 respectively, on both Win32 and X11 platforms.

 boldEnum and italicEnum control emboldening and italicization of a
 given typeface. These are specified with either RM_TRUE or RM_FALSE.
 Specifying RM_TRUE turns on either emboldening or italicization,
 while RM_FALSE turns them off.

 Justification control is provided in both the horizontal and vertical
 directions. Text is positioned with the use of either a 2D or 3D
 coordinate at the RMprimitive level. Justification controls where the
 text string appears in relationship to the on-screen projection of
 the vertex coordinate. Left-justified text will cause the text string
 to appear to the right of the projected vertex. Right-justified text
 will appear to the left of the project vertex. Similarly, RM_TOP will
 cause the text string to appear below the projected vertex, and
 RM_BOTTOM will cause the text string to appear above the projected
 vertex.
 
 @dend
 * ----------------------------------------------------
 */
RMenum
rmTextPropsSetAttribs (RMtextProps *p,
		       int font_enum,
		       int size_enum,
		       RMenum bold_enum,
		       RMenum italic_enum,
		       RMenum hJustify,
		       RMenum vJustify)
{
   int    parmsOK = 1;
   RMenum rstat = RM_CHILL;
   
   if (RM_ASSERT(p, "rmTextPropsSetAttribs() error: the input RMtextProps object pointer is NULL") == RM_WHACKED)
      return(RM_WHACKED);
   
   if (!((font_enum == RM_FONT_SERIF) || (font_enum == RM_FONT_SANS) || (font_enum == RM_FONT_MONO) ||
	 (font_enum == RM_FONT_SYMBOL) || (font_enum == RM_FONT_DINGBATS)))
      {
	 parmsOK = 0;
	 rmWarning("rmTextPropsSetAttribs error: the input font enumerator is not valid.");
      }
   
   if (!((size_enum == RM_FONT_XXS) || (size_enum == RM_FONT_XS) || (size_enum == RM_FONT_S) || (size_enum == RM_FONT_M) ||
	 (size_enum == RM_FONT_L) || (size_enum == RM_FONT_L) || (size_enum == RM_FONT_XL) || (size_enum == RM_FONT_XXL)))
      {
	 parmsOK = 0;
	 rmWarning("rmTextPropsSetAttribs error: the input size enumerator is not valid.");
      }
   
   if (!((bold_enum == RM_TRUE) || (bold_enum == RM_FALSE)))
      {
	 parmsOK = 0;
	 rmWarning("rmTextPropsSetAttribs error: the input embolden enumerator is neither RM_TRUE nor RM_FALSE.");
      }
   
   if (!((italic_enum == RM_TRUE) || (italic_enum == RM_FALSE)))
      {
	 parmsOK = 0;
	 rmWarning("rmTextPropsSetAttribs error: the input italicization enumerator is neither RM_TRUE nor RM_FALSE.");
      }
   
   if (!((hJustify == RM_LEFT) || (hJustify == RM_CENTER) || (hJustify == RM_RIGHT)))
      {
	 parmsOK = 0;
	 rmWarning("rmTextPropsSetAttribs error: the input horizontal justification enumerator is not one of RM_LEFT, RM_CENTER nor RM_FALSE.");
      }
   
   if (!((vJustify == RM_TOP) || (vJustify == RM_CENTER) || (vJustify == RM_BOTTOM)))
      {
	 parmsOK = 0;
	 rmWarning("rmTextPropsSetAttribs error: the input vertical justification enumerator is not one of RM_TOP, RM_CENTER nor RM_BOTTOM.");
      }
   
   if (parmsOK == 1)
      {
	 p->fontEnum = font_enum;
	 p->italicEnum = italic_enum;
	 p->boldEnum = bold_enum;
	 p->sizeEnum = size_enum;
	 p->hJustify = hJustify;
	 p->vJustify = vJustify;
	 rstat = RM_CHILL;
      }
   else
      rstat = RM_WHACKED;
   
   return(rstat);
}


/*
 * ----------------------------------------------------
 * @Name rmTextPropsGetAttribs
 @pstart
 RMenum rmTextPropsGetAttribs (const RMtextProps *toQuery,
		               int *fontEnumReturn,
			       int *sizeEnumReturn,
			       RMenum *boldEnumReturn,
			       RMenum *italicEnumReturn,
			       RMenum *hJustifyReturn,
			       RMenum *vJustifyReturn)
 @pend

 @astart
 const RMtextProps *toQuery - a handle to an RMtextProps object
    (input).

 int *fontEnumReturn, *sizeEnumReturn, *boldEnumReturn,
    *italicEnumReturn - handles to return caller-supplied integers
    (modified).

 RMenum hJustifyReturn, *vJustifyReturn - handles to return
    caller-supplied RMenums (modified).  @aend

 @dstart

 Use this routine to obtain the current text properties from an
 RMtextProps object. For each non-null RMenum parameter, the
 corresponding attribute is copied from the RMtextProps object into
 caller-supplied memory.

 Returns RM_CHILL upon success, or RM_WHACKED upon failure.

 See rmTextPropsSetAttributes for a description of the meaning of each
 of the text property parameters.

 @dend
 * ----------------------------------------------------
 */
RMenum
rmTextPropsGetAttribs (const RMtextProps *p,
		       int *font_enum,
		       int *size_enum,
		       RMenum *bold_enum,
		       RMenum *italic_enum,
		       RMenum *hJustify,
		       RMenum *vJustify)
{
    if (RM_ASSERT(p, "rmTextPropsGetAttribs() error: the input RMtextProps object pointer is NULL") == RM_WHACKED)
	return(RM_WHACKED);

    if (font_enum != NULL)
	*font_enum = p->fontEnum;

    if (size_enum != NULL)
	*size_enum = p->sizeEnum;

    if (bold_enum != NULL)
	*bold_enum = p->boldEnum;

    if (italic_enum != NULL)
	*italic_enum = p->italicEnum;

    if (hJustify != NULL)
	*hJustify = p->hJustify;

    if (vJustify != NULL)
	*vJustify = p->vJustify;

    return(RM_CHILL);
}


/*
 *
 * RM internal font registry info:
 *
 * there is a finite number of different fonts that are supported through
 * the RM interface. The number is computed as the product of the
 * number of font families with the number of font sizes and the number
 * of font styles.
 *
 * The font registry is an array of length (font_styles * font_sizes *
 *  font_styles). Each font registry object contains info about the
 * font, once initialized. The info consists of an OpenGL display list
 * base index and a boolean indicating whether or not the font has been
 * "initialized" (OpenGL bitmap display lists built).
 *
 * The RM font registry represents the rectification between X11 and
 * Win32 font handling. In Win32, the only way to render bitmap fonts
 * in OpeNGL is via Wgl, and wgl won't let you have access to the
 * raw bitmap data. Wgl encapsulates all rendered font bitmaps inside
 * OpenGL display lists.
 *
 * the font registry mechanism is used by both X11 and Win32 versions
 * of text rendering (and property querying) inside RM.
 */

/* PRIVATE */
RMfontRegistry *
private_rmFontRegistryNew(void)
{
   /* potential number of fonts available at once in RM */
   int num = RM_NUM_FONT_FACES * RM_NUM_FONT_SIZES * RM_NUM_FONT_STYLES;
   RMfontRegistry *f;

   f = (RMfontRegistry *)malloc(sizeof(RMfontRegistry)*num);
   
   if (f == NULL)
       return(NULL);

   memset((void *)f, 0, sizeof(RMfontRegistry)*num);

   return(f);
}

/* PRIVATE */
void
private_rmFontRegistryDelete(RMpipe *p,
			     RMfontRegistry *fontRegistry)
{
    RMfontRegistry *fr;
#ifdef RM_WIN
    HFONT           font;
#elif RM_X
    Font            font;
    XFontStruct     *xfs;
#endif
    int             fontEnum;
    int             sizeEnum;
    int             italicEnum;
    int             boldEnum;

    /* walk through all the font combinations, look for active fonts */
    for (fontEnum=0; fontEnum<RM_NUM_FONT_FACES; fontEnum++) 
    {
	for (sizeEnum=0; sizeEnum<RM_NUM_FONT_SIZES; sizeEnum++) 
	{
	    for (italicEnum=0; italicEnum<=1; italicEnum++) 
	    {
		for (boldEnum=0; boldEnum<=1; boldEnum++) 
		{
		    fr = private_rmFontRegistryEntry(fontEnum, sizeEnum,
						     italicEnum, boldEnum,
						     fontRegistry);
		    if (fr->initialized)
		    {
			glDeleteLists(fr->listbase, fr->listCount);
#ifdef RM_WIN
			font = (HFONT)(fr->fontinfo);
			DeleteObject(font);
#elif RM_X
			xfs = (XFontStruct *)(fr->fontinfo);
			font = xfs->fid;
			XFreeFont(rmxPipeGetDisplay(p), xfs);
#endif
		    }
		}   
	    }   
	}   
    }   

   free(fontRegistry);
}

/* PRIVATE */
int
private_rmFontRegistryIndex (int font_face,
			     int font_size,
			     int font_italic,
			     int font_embolden)
{
   /*
    * compute an index into the font registry table from the input
    * parms. this is a way of doing multidimensional array indexing.
    */

    int i, indx, xsize, xysize;

    xsize = RM_NUM_FONT_STYLES;
    xysize = xsize * RM_NUM_FONT_SIZES;

    i = 0;
    if (font_italic == RM_TRUE)
	i |= 1;
    if (font_embolden == RM_TRUE)
        i |= 2;

    indx = (font_face * xysize) + (font_size * xsize) + i;
    return(indx);
}


/* PRIVATE */
RMfontRegistry *
private_rmFontRegistryEntry (int font_face,
			     int font_size,
			     int font_italic,
			     int font_embolden,
			     RMfontRegistry *f)
{
    int indx = private_rmFontRegistryIndex(font_face, font_size, font_italic, font_embolden);

    if (f == NULL)
       return(NULL);

    return(f + indx);
}

/* PRIVATE */
void
private_rmTextPropsCopy(const RMtextProps *s,
			RMtextProps *d)
{
    d->fontEnum = s->fontEnum;
    d->italicEnum = s->italicEnum;
    d->boldEnum = s->boldEnum;
    d->sizeEnum = s->sizeEnum;
    d->hJustify = s->hJustify;
    d->vJustify = s->vJustify;
}
/* EOF */
