/*
    My own Int. 10h driven BIOS ROM graphics routines.  These will only
    work on the IBM-PC or compatable; and are recommended for use only
    with Microsoft 'C' Version 4.00 or later under MS-DOS 3.10 or later.
*/

#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define ROM_BIOS       0x10     /* INT 10H calls the IBM-PC ROM
                                   BIOS video driver services       */

#define DOS_INT        0x21     /* MS-DOS Int. 21h service call */

#define PRN_OUTPUT     0x05     /* Function 05h sends output to PRN: */

#define SET_VI_MODE    0x00     /* Function 00h sets the video mode
                                   calls.                           */

#define SET_PALETTE    0x0B     /* Function 0Bh sets the color
                                   palette for 320 X 200 medium-res */

#define WRITE_PIXEL    0x0C     /* Function 0Ch writes a pixel at
                                   location specified by CX & DX    */

#define READ_PIXEL     0x0D     /* Function 0Dh reads a pixel at
                                   location specified by CX & DX    */

#define GET_DIS_MODE   0x0F     /* Function 0Fh gets the current
                                   display mode and saves all the
                                   relevant information.            */

#define SELECT_PAGE    0x05     /* Function 05h selects the current
                                   active display page              */

extern void get_mode (void);
extern void set_mode (int);
extern void set_palette (int);
extern void set_background (int);
extern void plot_point (int, int, int);
extern void set_page (int);
extern void save_pic (char *);
extern void load_pic (char *);
extern int read_point (int, int);
extern void print_pic (void);
extern void prn_out (int);

FILE *PIC_STREAM;

union REGS inregs, outregs;
struct SREGS segregs;

char P_BUFFER[200] =   {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
			0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

int bits[8] = {1,2,4,8,16,32,64,128};

int CURRENT_PAGE = 0, CURRENT_MODE = 0, PALETTE = 0, BACKGROUND = 0,
    USE_MODE = 0;

void get_mode()
{
    int result;

    inregs.h.ah = GET_DIS_MODE;
    result = int86x(ROM_BIOS, &inregs, &outregs, &segregs);
    CURRENT_PAGE = outregs.h.bh;
    CURRENT_MODE = outregs.h.al;

} /* End of GET_MODE */

void set_mode(mode_val)
int mode_val;
{
    int result;

    USE_MODE = mode_val;
    inregs.h.ah = SET_VI_MODE;
    inregs.h.al = mode_val;
    result = int86x(ROM_BIOS, &inregs, &outregs, &segregs);

} /* End of SET_MODE */

void set_palette(palette_val)
int palette_val;
{
    int result;

    if (USE_MODE == 6)
	return;
    PALETTE = palette_val;
    inregs.h.ah = SET_PALETTE;
    inregs.h.bh = 1;
    inregs.h.bl = palette_val;
    result = int86x(ROM_BIOS, &inregs, &outregs, &segregs);

} /* End of SET_PALETTE */

void set_background(background_val)
int background_val;
{
    int result;

    if (USE_MODE == 6)
	return;
    BACKGROUND = background_val;
    inregs.h.ah = SET_PALETTE;
    inregs.h.bh = 0;
    inregs.h.bl = background_val;
    result = int86x(ROM_BIOS, &inregs, &outregs, &segregs);

} /* End of SET_BACKGROUND */

void plot_point(x_val, y_val, plot_color)
int x_val, y_val, plot_color;
{
    int result, max_col, max_row;

    max_row = 199;
    switch (USE_MODE) {
	case 4:              /* 320 X 200, 4 color */
	case 5:              /* 320 X 200, 4 color (burst off) */
	    max_col = 319;
	    break;
	case 6:              /* 640 X 200, 2 color */
	    max_col = 639;
	    break;
    }
    if (x_val < 0 )
	x_val = 0;
    if (x_val > max_col)
	x_val = max_col;
    if (y_val < 0)
	y_val = 0;
    if (y_val > max_row)
	y_val = max_row;
    
    inregs.h.ah = WRITE_PIXEL;
    inregs.h.al = plot_color;
    inregs.x.cx = x_val;
    inregs.x.dx = y_val;
    result = int86x(ROM_BIOS, &inregs, &outregs, &segregs);

} /* End of PLOT_POINT */

void set_page(page_num)
int page_num;
{
    int result;

    inregs.h.al = SELECT_PAGE;
    inregs.h.al = page_num;
    result = int86x(ROM_BIOS, &inregs, &outregs, &segregs);

} /* End of SET_PAGE */

int read_point(n_col,n_row)
int n_col, n_row;
{
    int result;

    inregs.h.ah = READ_PIXEL;
    inregs.x.cx = n_col;
    inregs.x.dx = n_row;
    result = int86x(ROM_BIOS, &inregs, &outregs, &segregs);
    return (outregs.h.al);

} /* End of READ_POINT */

void save_pic(save_fname)
char *save_fname;
{
    int wr_result, row_num, col_num, max_col, p_num;

    switch (USE_MODE) {
	case 4:
	case 5:
	    max_col = 320;
	    break;
	case 6:
	    max_col = 640;
	    break;
    }

    PIC_STREAM = fopen(save_fname,"w+b");

    for (col_num=0;col_num<max_col;col_num++) {
	for (row_num=0;row_num<=199;row_num++) {
	    p_num = (read_point(col_num,row_num) + 32);
	    P_BUFFER[row_num] = p_num;
	}
	wr_result = fwrite((char *)P_BUFFER,sizeof(char),200,PIC_STREAM);
    }
    fclose(PIC_STREAM);

} /* End of SAVE_PIC */

void load_pic(save_fname)
char *save_fname;
{
    int seek_result, row_num, col_num, max_col;

    switch (USE_MODE) {
	case 4:
	case 5:
	    max_col = 320;
	    break;
	case 6:
	    max_col = 640;
	    break;
    }

    PIC_STREAM = fopen(save_fname,"r+b");
    seek_result = fseek(PIC_STREAM,0L,SEEK_SET);

    for (col_num=0;col_num<max_col;col_num++) {
	seek_result = fread((char *)P_BUFFER,sizeof(char),200,PIC_STREAM);
	for (row_num=0;row_num<=199;row_num++) {
	    plot_point(col_num,row_num,((int)P_BUFFER[row_num] - 32));
	}
    }

    fclose(PIC_STREAM);

} /* End of LOAD_PIC */

void print_pic()
{
    int pr_num, row_num, col_num, max_col, pix_val, row_offset, max_offset;

    if (USE_MODE == 4 || USE_MODE == 5) {
	max_col = 320;
    }
    else {
	max_col = 640;
    }
    max_offset = 4;

    prn_out(27);        /* <ESC> */
    prn_out((int)'A');  /* "A" */
    prn_out(8);         /* <BS> */
    for (row_num=0;row_num<200;row_num+=max_offset) {
	prn_out(27);        /* <ESC> */
	prn_out((int)'*');  /* "*" */
	prn_out(4);         /* chr$(4) */
	prn_out(128);   /* n1 = 128 */
	prn_out(2);     /* n2 = 2  Graphic number = 128 + 512 = 640 */
	/* Set Graphic Print Mode  1:0.9 Vert.:Horiz. */
	for (col_num=0;col_num<max_col;col_num++) {
	    pr_num = 0;
	    for (row_offset=0;row_offset<max_offset;row_offset++) {
		pix_val = read_point(col_num, (row_num+row_offset));
		if (pix_val == 0) {
		    pr_num = (pr_num | bits[7 - (2 * row_offset)]);
		    pr_num = (pr_num | bits[6 - (2 * row_offset)]);
		}

	    }  /* Next row_offset */
	    prn_out(pr_num);  /* Print the graphics block needed */
	    if (USE_MODE == 4 || USE_MODE == 5)
		prn_out(pr_num);   /* Print it again if we're in 320 x 200 */

	}      /* Next col_num */
	prn_out(10);  /* <LF> */

    }          /* Next row_num */
    prn_out(12);      /* <FF> */

} /* End of PRINT_PIC */

void prn_out(out_char)
int out_char;
{
    int result;

    inregs.h.ah = PRN_OUTPUT;
    inregs.h.dl = (char)out_char;

    result = int86x(DOS_INT, &inregs, &outregs, &segregs);

}  /* End of PRN_OUT */

