#include "stdio.h"
#include "boolean.h"
#include "stdlib.h"
#include "memory.h"

#include "font.h"

static boolean font_initialized = false;
static unsigned char far * font_table = NULL;
static unsigned char far * rom_font_table = NULL;

/****************************************************************************
*                               init_font_table
* Inputs:
*       unsigned char size:
* Result: void
*       
* Effect: 
*       Loads default ROM font for display
****************************************************************************/

void init_font_table(unsigned char size)
    {
     if(size == 14)
	_asm{
          	mov ah,0x11;
		mov al, 1;
		mov bl, 0;
		int 0x10;
	    }
     else
	_asm {
		mov ah,0x11;
		mov al,4;
		mov bl,0;
		int 0x10;
	     }
    }

/****************************************************************************
*                               get_font_table
* Result: unsigned char far *
*       Pointer to font table, or NULL if error
* Notes: 
*       Fetches using BIOS EGA/VGA calls
****************************************************************************/

unsigned char far * get_font_table(unsigned char size)
    {
     unsigned char sizecode;

     if(size == 14)
	sizecode = 2;	/* ROM 8x14 font */
     else
     if(size == 16)
	sizecode = 6;	/* ROM 8x16 font */
     else
     return NULL;

     _asm {
     		push bp;
		push ds;
		push es;
		mov  bh, sizecode;	/* ROM 8xN font */
		mov  ah, 0x11;	/* function 11h  */
		mov  al, 0x30;  /* subfunction 30h: Get Font Information */
		int  10h;	/* do it */
		mov  ax, bp;	/* return value */
		mov  dx, es;	/* ... */
		pop es;
		pop ds;
		pop bp;
	  }
    }

/****************************************************************************
*                               set_font_table
* Inputs:
*       unsigned char far * tbl: Table
* Result: void
*       
* Effect: 
*       Sets the font table
****************************************************************************/

void set_font_table(unsigned char far * table, unsigned char sizecode)
    {
     _asm {
           push es;
	   push bp;
	   push bx;
	   push cx;
	    /* This used to say les bp,table, but bp is essential for
	       addressing 'table' and 'sizecode', so we have to first
	       move it to bx, then move bx to bp later via the stack
	    */
     	    les bx,table;	
	    push bx;
	    push es;
	    mov dx,0;		/* first char in table */
	    mov cx,256;		/* number of chars in table */
	    mov bl,0;		/* block */
	    mov bh,sizecode;	/* points per char */
	    mov al,0;		/* subfunction 0 */
	    mov ah,0x11;	/* function 11 */
	    pop es;
	    pop bp;		/* es:bp is font pointer */
	    int 0x10;		/* load user font and reprogram */
	   pop cx;
	   pop bx;
	   pop bp;
	   pop es;
	  }
    }

/****************************************************************************
*                                   fontset
* Inputs:
*       unsigned char ch: Destination for bits
*	unsigned char * bits: Bits to set
*	unsigned char len: Length
*	unsigned char size: Table entry size
* Result: boolean
*       true if success
*	false if error
* Effect: 
*       Sets the 'bits' for length 'len' into the font map at position
*	'ch'
****************************************************************************/

boolean fontset(unsigned char ch, unsigned char * bits, unsigned char len,
		unsigned char size)
    {
     unsigned char far * maploc;

     if(!font_initialized)
        { /* get font */
	 init_font_table(size);
	 rom_font_table = get_font_table(size);
	 font_table = malloc( size * 256);
	 if(font_table == NULL)
	    return false;
	 _fmemcpy(font_table, rom_font_table, size*256);
	 font_initialized = true;
	} /* get font */

     maploc = &font_table[size * ch ];
     _fmemcpy(maploc, bits, len);
     set_font_table(font_table, size);
     return true;
    }
