Source file: /~heha/hs/dos/hp2xx_hs.zip/chardraw.c

/* Copyright (c) 1991 - 1994 Heinz W. Werntges.  All rights reserved.
   Parts Copyright (c) 1999 -2000  Martin Kroeker  All rights reserved.
*/

/** CHARDRAW.c: Implementation of characters by draw/move commands
 **
 ** 92/02/19 HWW  V 1.00b Derived from pplib.cpp and sprite.cpp (V 1.2)
 ** 92/02/27 HWW  V 2.00b Many changes - last: bug fixed in adjust_text_par()
 ** 92/03/03 HWW  V 2.01a LB != PB: acknowledged by introducing LB_Mode
 ** 92/04/28 HWW  V 2.01b VAX seems to mix up tp & TP --> TEXTP instead
 ** 92/05/28 HWW  V 2.02a plot_symbol_char() added
 ** 92/10/15 HWW  V 2.02b Line types acknowledged
 ** 92/10/17 HWW  V 2.03  RS6000 bug fixed in code_to_ucoord()
 ** 93/02/09 HWW  V 2.03b Comments added; prepared for more fonts;
 **			  Font OV bug fixed (8-bit codes now checked!)
 ** 93/04/13 HWW  V 2.04a plot_user_char() added (code by A. Treindl)
 ** 94/01/02 HWW  V 2.05a Symbol plotting: improved centering (L. Lowe)
 ** 94/02/14 HWW  V 2.05b Adapted to changes in hp2xx.h
 **/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "bresnham.h"
#include "hp2xx.h"
#include "lindef.h"
#include "chardraw.h"
#include "charset0.h"
#include "charset1.h"
#include "charset2.h"
#include "charset3.h"
#include "charset4.h"
#include "charset5.h"
#include "charset6.h"
#include "charset7.h"

/**
 ** NOTE: There is code here masked off by symbol STROKED_FONTS
 ** In an earlier version it had some meaning but is now inactive.
 ** I left it here in the hope that some day it may resume its
 ** earlier purpose which was:
 **   Loading of external fonts (here: Hershey fonts as within the
 **   Borland BGI fonts.)
 **/

extern	HPGL_Pt		HP_pos, P1, P2;

extern int iwflag;
extern short scale_flag;
extern int mode_vert;
extern HPGL_Pt		C1,C2;
extern HPGL_Pt S1,Q;
TEXTPAR	TEXTP, *tp = &TEXTP;



static void
code_to_ucoord (char c, HPGL_Pt *pp)
/**
 ** Converts internal one-byte code (in c) for a character vector
 ** into HP-GL coordinates (pointed to by pp)
 **/
{
double	x,y;

  /*
   * RS6000 bug fix:
   * 	outer braces of casts removed, costing 2 double ops
   * My guess: "char" is unsigned on RS6000
   */
  x = (double) (c >> 4)   - 1.0;	/* Bits 4,5,6 --> value 0..7 */
  y = (double) (c & 0x0f) - 4.0;	/* Bits 0-3   --> value 0..f */

  pp->x = tp->Txx * x + tp->Txy * y + tp->refpoint.x + tp->offset.x;
  pp->y = tp->Tyx * x + tp->Tyy * y + tp->refpoint.y + tp->offset.y;
}




static void
ASCII_to_char (int c)
/**
 ** Main user interface: Convert ASCII code c into a sequence
 ** of move/draw vectors which draw a corresponding character
 **/
{
HPGL_Pt	p;
char	*ptr;
int outside=0;

  int SafeLineType = CurrentLineType;
  CurrentLineType = LT_solid;

  switch (tp->font)
  {
    case 0:	/* charset 0, limited to 7 bit ASCII - 8bit addressing maps to charset 7	*/

	if (c & 0x80)
	{
		/*Eprintf ("8bit character mapped to charset 7\n");*/
		c+=128;
		ptr = &charset7[c][0];
	} else {
	ptr = &charset0[c][0];
	}
	break;

    case 1:	/* charset 1, 9825	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
if (c == 95 || c == 96 || c == 126 ) { /* backspacing for special characters  */ 
  tp->refpoint.x -= tp->chardiff.x;
  tp->refpoint.y -= tp->chardiff.y;
}
	ptr = &charset1[c][0];
	break;

    case 2:	/* charset 2, French/German	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
if (c == 39 || c == 94 || c == 95 || c == 96 || c == 123 || c == 124 || c == 125) { /* backspacing for special characters  */ 
  tp->refpoint.x -= tp->chardiff.x;
  tp->refpoint.y -= tp->chardiff.y;
  }
	ptr = &charset2[c][0];
	break;

    case 3:	/* charset 3, Scandinavian	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
if ( c == 95 || c >= 123 ) { /* backspacing for special characters  */ 
  tp->refpoint.x -= tp->chardiff.x;
  tp->refpoint.y -= tp->chardiff.y;
  }
	ptr = &charset3[c][0];
	break;

    case 4:	/* charset 4, Spanish/Latin American	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
if ( c == 39  || c == 94 || c == 95 || c >= 123 ) { /* backspacing for special characters  */ 
  tp->refpoint.x -= tp->chardiff.x;
  tp->refpoint.y -= tp->chardiff.y;
  }
	ptr = &charset4[c][0];
	break;

    case 5:	/* charset 5, Special Symbols	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
if (c == 101 ) { /* backspacing for special characters  */ 
  tp->refpoint.x -= tp->chardiff.x;
  tp->refpoint.y -= tp->chardiff.y;
  }
	ptr = &charset5[c][0];
	break;

    case 6:	/* charset 6, JIS ASCII	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
	ptr = &charset6[c][0];
	break;

    case 7:	/* charset 7, 'HP Roman 8', limited to 7 bit ASCII	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
	ptr = &charset7[c][0];
	break;

    default:	/* Currently, only charsets 0-7 are supported	*/
	Eprintf ("Charset %d not supported -- replaced by charset 0!\n", tp->font);
	if (c & 0x80)
	{
		/*Eprintf ("8bit character mapped to charset 7\n");*/
		c+=128;
		ptr = &charset7[c][0];
	} else {
	ptr = &charset0[c][0];
	}
	break;
  }

  for (; *ptr; ptr++)	/* Draw this char	*/
  {
	code_to_ucoord ((char)(*ptr&0x7f), &p);
/*MK*/

  if (iwflag)
      {
      if (scale_flag) {
	if ( P1.x+p.x > C2.x || P1.y+p.y > C2.y){
		fprintf(stderr,"A2C IW set:point %f %f >P2\n",p.x,p.y);
		outside=1;
 		}
	if ( P1.x+p.x  < C1.x  || P1.y+p.y < C1.y) {
 		fprintf(stderr,"A2C IW set:point  %f %f <P1\n",p.x,p.y);
 		outside=1;
  		}
      }else{
      if (P1.x + (p.x - S1.x) * Q.x > C2.x || P1.y + (p.y - S1.y) * Q.y > C2.y)
       {
       /*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
       outside = 1;
       }
      if (P1.x + (p.x - S1.x) * Q.x < C1.x || P1.y + (p.y - S1.y) * Q.y < C1.y)
       {
       /*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
       outside = 1;
       }
     }
  }                                                                    

	if ((*ptr & 0x80) && !outside)	/* High bit is draw flag */
		Pen_action_to_tmpfile (DRAW_TO, &p, FALSE);
	else 
		Pen_action_to_tmpfile (MOVE_TO, &p, FALSE);
  
  outside = 0;
  }

  /* Update cursor: to next character origin!	*/

  tp->refpoint.x += tp->chardiff.x;
  tp->refpoint.y += tp->chardiff.y;
  CurrentLineType = SafeLineType;


}


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

void
init_text_par (void)
{
  tp->width	= 0.005  * (P2.x - P1.x);
  tp->height	= 0.0075 * (P2.y - P1.y);
  tp->espace	= 0.0;
  tp->eline	= 0.0;
  tp->dir	= 0.0;
  tp->slant	= 0.0;
  tp->font	= 0;
  tp->orig	= 1;			/* Font number: 0 = old	*/
  tp->refpoint	= tp->CR_point = HP_pos;
  tp->offset.x	= tp->offset.y = 0.0;
  adjust_text_par();
}




void
adjust_text_par (void)
/**
 ** Width, height, space, line, dir, slant
 ** as given in structure declaration
 **/
{
double	cdir,sdir;

/**
 ** Here, we use space & line as basic data, since these parameters
 ** are affected by SI and SR commands, not width or height!
 **/
  tp->space	=  tp->width  * 1.5;
  tp->line	=  tp->height * 2.0;

  cdir		=  cos (tp->dir);
  sdir		=  sin (tp->dir);
  tp->Txx	=  tp->width * cdir / 4.0;
  tp->Tyx	=  tp->width * sdir / 4.0;
  tp->Txy	=  tp->height* (tp->slant * cdir - sdir) / 6.0;
  tp->Tyy	=  tp->height* (tp->slant * sdir + cdir) / 6.0;

  tp->chardiff.x=  tp->space * (1.0 + tp->espace) * cdir;
  tp->chardiff.y=  tp->space * (1.0 + tp->espace) * sdir;
  tp->linediff.x=  tp->line  * (1.0 + tp->eline ) * sdir;
  tp->linediff.y= -tp->line  * (1.0 + tp->eline ) * cdir;

#ifdef STROKED_FONTS
  if (init_font (tp->font))
  {
	Eprintf ("\007 init_font() failed for font #%d\n", tp->font);
	Eprintf ("Font 0 used instead!\n");
	tp->font = 0;
  }
#endif
}



#define	HEIGHT_FAC	0.666666666
#define	WIDTH_FAC	0.666666666


static void
get_label_offset (char *txt, LB_Mode mode)
/**
 ** Depending on the current HP-GL label mode, a string may have different
 ** x and y offsets. These offsets are accounted for here:
 **/
{
float		dx=0.0, dy=0.0;
static	float	nc, nl, nc_max;

  switch (mode)
  {
    case LB_direct:	/* Get number of printable plot cells	*/
	nc = nl = nc_max = 0.0;
	for (; *txt && *txt != _CR; txt++)	/* to ETX or CR */
		if (*txt >=' ' && ((*txt&'\x80') == 0))
			nc++;			/* Printable ?	*/
		else if (*txt == _BS)		/* Backspace ?	*/
			nc--;
		else if (*txt == _HT)
			nc -= 0.5;
	break;

    case LB_buffered:
	/* Max number of printable plot cells + lines	*/
	nc = nl = nc_max = 0.0;
	for (; *txt; txt++)
		if (*txt >=' ' && ((*txt&'\x80') == 0))
			nc++;
		else if (*txt == _BS)
			nc--;
		else if (*txt == _HT)
			nc -= 0.5;
		else if (*txt == _LF)
			nl++;
		else if (*txt == _VT)
			nl--;
		else if (*txt == _CR)
		{
			if (nc > nc_max)
				nc_max = nc;
			nc = 0.0;
		}
	if (nc > nc_max)
		nc_max = nc;
	nc = nc_max;	/* Use longest row for adjustment	*/
	break;

    case LB_buffered_in_use:
	break;	/* Use data from earlier LB_buffered call	*/
  }

  switch (tp->orig)
  {
	case  1:
	case  2:
	case  3:
		dx = 0.0;
		break;
	case 11:
	case 12:
	case 13:
		dx = 0.5 * WIDTH_FAC;
		break;
	case  4:
	case  5:
	case  6:
	case 14:
	case 15:
	case 16:
		dx = 0.5 * (1.0 - WIDTH_FAC);
		tp->refpoint.x -= tp->chardiff.x * nc/2.0;
		tp->refpoint.y -= tp->chardiff.y * nc/2.0;
		break;
	case  7:
	case  8:
	case  9:
		dx = 1.0 - WIDTH_FAC;
		tp->refpoint.x -= tp->chardiff.x * nc;
		tp->refpoint.y -= tp->chardiff.y * nc;
		break;
	case 17:
	case 18:
	case 19:
		dx = 1.0 - 1.5 * WIDTH_FAC;
		tp->refpoint.x -= tp->chardiff.x * nc;
		tp->refpoint.y -= tp->chardiff.y * nc;
		break;
  }

  switch (tp->orig)
  {
	case  1:
	case  4:
	case  7:
		dy = 0.0;
		if (mode == LB_buffered || mode == LB_buffered_in_use)
		{
			tp->refpoint.x -= tp->linediff.x * nl;
			tp->refpoint.y -= tp->linediff.y * nl;
		}
		break;
	case 11:
	case 14:
	case 17:
		dy = 0.5 * HEIGHT_FAC;
		if (mode == LB_buffered || mode == LB_buffered_in_use)
		{
			tp->refpoint.x -= tp->linediff.x * nl;
			tp->refpoint.y -= tp->linediff.y * nl;
		}
		break;
	case  2:
	case  5:
	case  8:
	case 12:
	case 15:
	case 18:
		dy = -0.5 * HEIGHT_FAC;
		if (mode == LB_buffered || mode == LB_buffered_in_use)
		{
			tp->refpoint.x -= tp->linediff.x * nl/2.0;
			tp->refpoint.y -= tp->linediff.y * nl/2.0;
		}
		break;
	case  3:
	case  6:
	case  9:
		dy = -HEIGHT_FAC;
		if (mode == LB_buffered || mode == LB_buffered_in_use)
		{
			tp->refpoint.x += tp->linediff.x * (nl-1.0);
			tp->refpoint.y += tp->linediff.y * (nl-1.0);
		}
		break;
	case 13:
	case 16:
	case 19:
		dy = -1.5 * HEIGHT_FAC;
		if (mode == LB_buffered || mode == LB_buffered_in_use)
		{
			tp->refpoint.x += tp->linediff.x * (nl-1.0);
			tp->refpoint.y += tp->linediff.y * (nl-1.0);
		}
		break;
  }

  tp->offset.x = tp->chardiff.x * dx - tp->linediff.x * dy;
  tp->offset.y = tp->chardiff.y * dx - tp->linediff.y * dy;
}




void
plot_string (char *txt, LB_Mode mode)
/**
 ** String txt cannot simply be processed char-by-char. Depending on
 ** the current label mode, its origin must first be calculated properly.
 ** Then, there are some special control characters which affect cursor
 ** position but don't draw anything. Finally, characters can be drawn
 ** one-by-one.
 **/
{
char	*txt0;

  txt0 = txt;
  tp->refpoint = HP_pos;
  get_label_offset (txt, mode);

  while (*txt)
  {
	switch (*txt)
	{
	  case ' ':
		tp->refpoint.x += tp->chardiff.x;
		tp->refpoint.y += tp->chardiff.y;
		break;
	  case _CR:
	  	if (mode_vert) tp->CR_point.y -= tp->linediff.y ; 
		tp->refpoint = tp->CR_point;
		switch (mode)
		{
		  case LB_direct:
			get_label_offset (txt+1, mode);
			break;
		  case LB_buffered:
			get_label_offset (txt0, LB_buffered_in_use);
			break;
		  default:
			break;
		}
		break;
	  case _LF:
		tp->CR_point.x += tp->linediff.x;
		tp->refpoint.x += tp->linediff.x;
		if (!mode_vert){
		tp->CR_point.y += tp->linediff.y;
		tp->refpoint.y += tp->linediff.y;
		}else{
		tp->refpoint.y -= tp->linediff.y;
		}
		break;
	  case _BS:
		tp->refpoint.x -= tp->chardiff.x;
		tp->refpoint.y -= tp->chardiff.y;
		break;
	  case _HT:
		tp->refpoint.x -= 0.5 * tp->chardiff.x;
		tp->refpoint.y -= 0.5 * tp->chardiff.y;
		break;
	  case _VT:
		tp->CR_point.x -= tp->linediff.x;
		tp->CR_point.y -= tp->linediff.y;
		tp->refpoint.x -= tp->linediff.x;
		tp->refpoint.y -= tp->linediff.y;
		break;
	  case _SO:
	  	if (tp->altfont)
	  	tp->font = tp->altfont;
		break;
	  case _SI:	
	  	tp->font = tp->stdfont;
		break;
	  default:
#ifdef STROKED_FONTS
		if (tp->font)
			ASCII_to_font ((int) *txt);
		else
#endif
			ASCII_to_char ((int) *txt);
	       break;
	}
/**
 ** Move to next reference point, e. g. the next character origin
 **/
        if (mode_vert) {
        tp->refpoint.x -= tp->chardiff.x;
        tp->refpoint.y += tp->linediff.y;
        }
	Pen_action_to_tmpfile (MOVE_TO, &tp->refpoint, FALSE);
	txt++;
  }
}





static void
ASCII_set_center (int c)
/**
 ** Convert ASCII code c into a sequence of move/draw vectors
 ** and determine their "center of gravity"
 **/
{
HPGL_Pt	p, center;
int	cnt;
char	*ptr;

  switch (tp->font)
  {

    case 0:	/* charset 0, limited to 7 bit ASCII - 8bit addressing maps to charset 7	*/

	if (c & 0x80)
	{
		Eprintf ("8bit character mapped to charset 7\n");
		c+=128;
		ptr = &charset7[c][0];
	} else {
	ptr = &charset0[c][0];
	}
	break;

    case 5:	/* charset 5, limited to 7 bit ASCII	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
	ptr = &charset5[c][0];
	break;

    case 7:	/* charset 7, 'HP Roman 8', limited to 7 bit ASCII	*/

	if (c & 0x80)
	{
		Eprintf ("Illegal char in string: %d = %c replaced by blank!\n", c,c);
		c = ' ';
	}
	ptr = &charset7[c][0];
	break;

    default:	/* Currently, there is just one charset	*/
	Eprintf ("Charset %d not supported -- replaced by blank!\n", tp->font);
		c = ' ';
	ptr = &charset0[c][0];
	break;
  }

  center.x = center.y = 0.0;
  for (cnt=0; *ptr; ptr++, cnt++)	/* Scan this char	*/
  {
	code_to_ucoord ((char)(*ptr&0x7f), &p);
	center.x += p.x;
	center.y += p.y;
  }
  if (cnt)
  {
	tp->offset.x = -center.x / cnt;
	tp->offset.y = -center.y / cnt;
  }
  else		/* Should never happen:	*/
	tp->offset.x = tp->offset.y = 0.0;
}




static void
set_symbol_center (char c)
/**
 ** Symbol plotting requires a special x and y offset for proper
 ** symbol-specific centering
 **/
{
  tp->refpoint.x= 0.0;
  tp->refpoint.y= 0.0;
  tp->offset.x	= 0.0;
  tp->offset.y	= 0.0;
  ASCII_set_center (c);
  tp->refpoint.x= HP_pos.x;	/*  - tp->chardiff.x / 2.0; */
  tp->refpoint.y= HP_pos.y;	/*  - tp->chardiff.y / 2.0; */
}




void
plot_symbol_char (char c)
/**
 ** Special case: Symbol plotting. This requires a special
 ** x and y offset (for proper centering) but then simply amounts to
 ** drawing a single character.
 **/
{
  set_symbol_center (c);

#ifdef STROKED_FONTS
  if (tp->font)
	ASCII_to_font ((int) c);
  else
#endif
	ASCII_to_char ((int) c);

/**
 ** Move to next reference point, e. g. the next character origin
 **/
  Pen_action_to_tmpfile (MOVE_TO, &tp->refpoint, FALSE);
}




void
plot_user_char (FILE *hd)
/**
 ** added by Alois Treindl 12-apr-93
 **/
{
HPGL_Pt	p;
double	x, y;
float	fx, fy;
int	pendown = FALSE;

  int SafeLineType = CurrentLineType; /* Save Current Line Type */
  CurrentLineType  = LT_solid;

  tp->refpoint		= HP_pos;
  p.x = tp->refpoint.x + tp->offset.x;
  p.y = tp->refpoint.y + tp->offset.y;

  while (read_float(&fx, hd) == 0)
  {
	if (fx >= 99)
		pendown = TRUE;
	else if (fx <= -99)
		pendown = FALSE;
	else
	{
		if (read_float(&fy, hd) != 0)
			break;
		x = fx;
		y = fy * 2.0 / 3.0;
		p.x += tp->Txx * x + tp->Txy * y;
		p.y += tp->Tyx * x + tp->Tyy * y;
		if (pendown)
			Pen_action_to_tmpfile (DRAW_TO, &p, FALSE);
		else
			Pen_action_to_tmpfile (MOVE_TO, &p, FALSE);
	}
  }

  /* Update cursor: to next character origin!   */

  tp->refpoint.x += tp->chardiff.x;
  tp->refpoint.y += tp->chardiff.y;
  Pen_action_to_tmpfile (MOVE_TO, &tp->refpoint, FALSE);

  CurrentLineType = SafeLineType; /* restore LineType */
}

Detected encoding: UTF-80