/*
 * $Id: pbm.trm,v 1.9 1995/12/20 21:48:03 drd Exp $
 *
 */

/* GNUPLOT - pbm.trm */
/*
 * Copyright (C) 1990 - 1993   
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted, 
 * provided that the above copyright notice appear in all copies and 
 * that both that copyright notice and this permission notice appear 
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the modified code.  Modifications are to be distributed 
 * as patches to released version.
 *  
 * This software  is provided "as is" without express or implied warranty.
 * 
 * This file is included by ../term.c.
 *
 * This terminal driver supports:
 *  pbm
 *
 * AUTHORS
 *  Russell Lang
 *
 * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
 * 
 */

/* The following pbmplus drivers use the generic bit mapped graphics
   routines from bitmap.c to build up a bit map in memory.  The driver
   interchanges colomns and lines in order to access entire lines
   easily and returns the lines to get bits in the right order :
   (x,y) -> (y,XMAX-1-x). */
/* This interchange is done by calling b_makebitmap() with reversed 
   xmax and ymax, and then setting b_rastermode to TRUE.  b_setpixel()
   will then perform the interchange before each pixel is plotted */
/* See Jef Poskanzer's excellent PBMplus package for more details of
   the Portable BitMap format and for programs to convert PBM files  
   to other bitmap formats. */

#ifndef GOT_DRIVER_H
#include "driver.h"
#endif

#ifdef TERM_REGISTER
register_term(pbm_driver)
#endif

#ifdef TERM_PROTO
TERM_PUBLIC void PBMoptions __P((void));
TERM_PUBLIC void PBMinit __P((void));
TERM_PUBLIC void PBMreset __P((void));
TERM_PUBLIC void PBMsetfont __P((void));
TERM_PUBLIC void PBMgraphics __P((void));
TERM_PUBLIC void PBMmonotext __P((void));
TERM_PUBLIC void PBMgraytext __P((void));
TERM_PUBLIC void PBMcolortext __P((void));
TERM_PUBLIC void PBMtext __P((void));
TERM_PUBLIC void PBMlinetype __P((int linetype));
TERM_PUBLIC void PBMpoint __P((unsigned int x, unsigned int y, int point));
#endif /* TERM_PROTO */

#ifdef TERM_BODY

/* make XMAX and YMAX a multiple of 8 */
#define PBM_XMAX (640)
#define PBM_YMAX (480)
#define PBM_VCHAR (FNT5X9_VCHAR)
#define PBM_HCHAR (FNT5X9_VCHAR)
#define PBM_VTIC FNT5X9_HBITS
#define PBM_HTIC FNT5X9_HBITS

static int pbm_font=1;	/* small font */
static int pbm_mode=0;  /* 0:monochrome 1:gray 2:color */

/* 7=black, 0=white */
static int pgm_gray[]={7,1,6,5,4,3,2,1,7};  /* grays  */
/* bit3=!intensify, bit2=!red, bit1=!green, bit0=!blue */
static int ppm_color[]={15,8,3,5,6,4,2,1,11,13,14}; /* colors */

TERM_PUBLIC void PBMoptions()
{
  pbm_font=1;
  pbm_mode=0;

  term_options[0]='\0';

  while (!END_OF_COMMAND) {
    if (almost_equals(c_token,"s$mall"))
      pbm_font=1;
    else if (almost_equals(c_token,"me$dium"))
      pbm_font=2;
    else if (almost_equals(c_token,"l$arge"))
      pbm_font=3;
    else if (almost_equals(c_token,"mo$nochrome"))
      pbm_mode=0;
    else if (almost_equals(c_token,"g$ray"))
      pbm_mode=1;
    else if (almost_equals(c_token,"c$olor"))
      pbm_mode=2;
    else {
      pbm_font=1; /* reset to default, since term is already set */
      pbm_mode=0;
      int_error("expecting: {small, medium, large} and {monochrome, gray, color}",c_token);
    }
    c_token++;
  }

  /* setup options string */

  switch(pbm_font) {
    case 1: strcat(term_options,"small"); break;
    case 2: strcat(term_options,"medium"); break;
    case 3: strcat(term_options,"large"); break;
  }

  switch(pbm_mode) {
    case 0: strcat(term_options," monochrome"); break;
    case 1: strcat(term_options," gray"); break;
    case 2: strcat(term_options," color"); break;
  }
}


TERM_PUBLIC void PBMinit()
{
#ifdef REOPEN_BINARY
   reopen_binary();
#endif /* REOPEN_BINARY */
}


TERM_PUBLIC void PBMreset()
{
#ifdef vms
   fflush_binary();
#endif /* vms */
}


TERM_PUBLIC void PBMsetfont()
{
	switch(pbm_font) {
		case 1:
			b_charsize(FNT5X9);
			term->v_char = FNT5X9_VCHAR;
			term->h_char = FNT5X9_HCHAR;
			term->v_tic = FNT5X9_HBITS;
			term->h_tic = FNT5X9_HBITS;
			break;
		case 2:
			b_charsize(FNT9X17);
			term->v_char = FNT9X17_VCHAR;
			term->h_char = FNT9X17_HCHAR;
			term->v_tic = FNT9X17_HBITS;
			term->h_tic = FNT9X17_HBITS;
			break;
		case 3:
			b_charsize(FNT13X25);
			term->v_char = FNT13X25_VCHAR;
			term->h_char = FNT13X25_HCHAR;
			term->v_tic = FNT13X25_HBITS;
			term->h_tic = FNT13X25_HBITS;
			break;
	}
}


TERM_PUBLIC void PBMgraphics()
{
  int numplanes=1;

  switch(pbm_mode) {
    case 1: numplanes=3; break;
    case 2: numplanes=4; break;
  }

  PBMsetfont();
  /* rotate plot -90 degrees by reversing XMAX and YMAX and by 
  setting b_rastermode to TRUE */
  b_makebitmap((unsigned int)(PBM_YMAX*ysize),
               (unsigned int)(PBM_XMAX*xsize),numplanes);
  b_rastermode = TRUE;

  if(pbm_mode!=0)
    b_setlinetype(0); /* solid lines */
}


static void PBMmonotext()
{
  register int x,j,row;

   fprintf(outfile,"P4\n");
   fprintf(outfile,"%u %u\n", b_ysize, b_xsize);

   /* dump bitmap in raster mode */
   for (x = b_xsize-1; x >= 0; x--) {
      row = (b_ysize/8)-1;
      for (j = row; j >= 0; j--) {
         (void) fputc( (char)(*((*b_p)[j]+x)), outfile );
      }
   }

   b_freebitmap();
}

static void PBMgraytext()
{
  register int x,j,row;
  register int i,value;
  int mask, plane1, plane2, plane3;

   fprintf(outfile,"P5\n");
   fprintf(outfile,"%u %u\n", b_ysize, b_xsize);
   fprintf(outfile,"%u\n",7);

   /* dump bitmap in raster mode */
   for (x = b_xsize-1; x >= 0; x--) {
      row = (b_ysize/8)-1;
      for (j = row; j >= 0; j--) {
         mask = 0x80;
         plane1=(*((*b_p)[j]+x));
         plane2=(*((*b_p)[j+b_psize]+x));
         plane3=(*((*b_p)[j+b_psize+b_psize]+x));
         for (i=0; i<8; i++) {
            value=7;
            if (plane1 & mask)  value-=1;
            if (plane2 & mask)  value-=2;
            if (plane3 & mask)  value-=4;
            (void) fputc( (char)(value), outfile );
            mask>>=1;
         }
      }
   }

   b_freebitmap();
}

static void PBMcolortext()
{
  register int x,j,row;
  register int i;
  int mask, plane1, plane2, plane3, plane4;
  int red, green, blue;

   fprintf(outfile,"P6\n");
   fprintf(outfile,"%u %u\n", b_ysize, b_xsize);
   fprintf(outfile,"%u\n",3);

   /* dump bitmap in raster mode */
   for (x = b_xsize-1; x >= 0; x--) {
      row = (b_ysize/8)-1;
      for (j = row; j >= 0; j--) {
         mask = 0x80;
         plane1=(*((*b_p)[j]+x));
         plane2=(*((*b_p)[j+b_psize]+x));
         plane3=(*((*b_p)[j+b_psize+b_psize]+x));
         plane4=(*((*b_p)[j+b_psize+b_psize+b_psize]+x));
         for (i=0; i<8; i++) {
            red = (plane3 & mask) ? 1 : 3;
            green = (plane2 & mask) ? 1 : 3;
            blue = (plane1 & mask) ? 1 : 3;
            if (plane4 & mask) {
               red--; green--; blue--;
            }
            (void) fputc( (char)(red), outfile );
            (void) fputc( (char)(green), outfile );
            (void) fputc( (char)(blue), outfile );
            mask>>=1;
         }
      }
   }

   b_freebitmap();
}

TERM_PUBLIC void PBMtext()
{
  switch(pbm_mode) {
    case 0: PBMmonotext(); break;
    case 1: PBMgraytext(); break;
    case 2: PBMcolortext(); break;
  }
}


TERM_PUBLIC void PBMlinetype(linetype)
int linetype;
{
  switch(pbm_mode) {
    case 0:
      b_setlinetype(linetype);
    break;
    case 1:
      if (linetype>=7)
        linetype %= 7;
      b_setvalue(pgm_gray[linetype+2]);
    break;
    case 2:
      if (linetype>=9)
        linetype %= 9;
      b_setvalue(ppm_color[linetype+2]);
    break;
  }
}

TERM_PUBLIC void PBMpoint(x,y,point)
unsigned int x,y;
int point;
{
  if(pbm_mode==0) line_and_point(x,y,point);
  else            do_point(x,y,point);
}

#endif /* TERM_BODY */

#ifdef TERM_TABLE

#define PBMmove b_move
#define PBMvector b_vector
#define PBMtext_angle b_text_angle
#define PBMput_text b_put_text

TERM_TABLE_START(pbm_driver)
      "pbm", "Portable bitmap [small medium large] [monochrome gray color]",
       PBM_XMAX, PBM_YMAX, PBM_VCHAR,
       PBM_HCHAR, PBM_VTIC, PBM_HTIC, PBMoptions,
       PBMinit, PBMreset, PBMtext, null_scale,
       PBMgraphics, PBMmove, PBMvector, PBMlinetype,
       PBMput_text, PBMtext_angle, null_justify_text, PBMpoint,
       do_arrow, set_font_null,
			0, /* pointsize */
			TERM_CAN_MULTIPLOT
TERM_TABLE_END(pbm_driver)

#undef LAST_TERM
#define LAST_TERM pbm_driver

#endif /* TERM_TABLE */


#ifdef TERM_HELP
START_HELP(pbm)
"1 pbm",
"?set terminal pbm",
"?pbm",
" Several options may be set in the PBMplus driver.",
"",
" Syntax:",
"         set terminal pbm {<fontsize>} {<colormode>}",
"",
" where <fontsize> is `small`, `medium`, or `large` and <colormode> is",
" `monochrome`, `gray` or `color`.  Default size is 640 pixels wide and 480",
" pixels high.  The output for `monochrome` is a portable bitmap (one bit per",
" pixel).  The output for `gray` is a portable graymap (three bits per pixel).",
" The output for `color` is a portable pixmap (color, four bits per pixel).",
" The output of these drivers can be used with Jef Poskanzer's excellent",
" PBMPLUS package, which provides programs to convert the above PBMPLUS formats",
" to GIF, TIFF, MacPaint, Macintosh PICT, PCX, X11 bitmap and many others.",
"",
" Examples:",
"         set term pbm small",
"         set size 2,2",
"         set term pbm color medium"
END_HELP(pbm)
#endif
