/***************************************************************
 *  Alcuin: A HP48 emulator for Amiga Computers
 * 
 *  (C) 1995 Stephan Schupfer (schupfer@sbox.tu-graz.ac.at)
 *
 */

#include <stdio.h>
#include <graphics/gfx.h>
#include <intuition/intuition.h>
#include <exec/memory.h>
#include <cybergraphics/cybergraphics.h>
#include <inline/cybergraphics.h>

#include "A48.h"
#include "main.h"
#include "hp48.h"
#include "annunc.h"
#include "device.h"

#define DISP_ROWS			64
#define ALL_DISP			4608
#define NIBS_PER_BUFFER_ROW	36
#define EIGHT_ROW			288
#define NPR					33

extern void read_disp (long addr,unsigned char *val);
extern int Chunky;

struct {
	long r,g,b;
	} 
HP_Colors[13] = {
	{0x90ffffff,0x90ffffff,0x90ffffff},
	{0x84ffffff,0x84ffffff,0x84ffffff},
	{0x78ffffff,0x78ffffff,0x78ffffff},
	{0x6cffffff,0x6cffffff,0x6cffffff},
	{0x60ffffff,0x60ffffff,0x60ffffff},
	{0x54ffffff,0x54ffffff,0x54ffffff},
	{0x48ffffff,0x48ffffff,0x48ffffff},
	{0x3cffffff,0x3cffffff,0x3cffffff},
	{0x30ffffff,0x30ffffff,0x30ffffff},
	{0x24ffffff,0x24ffffff,0x24ffffff},
	{0x18ffffff,0x18ffffff,0x18ffffff},
	{0x0cffffff,0x0cffffff,0x0cffffff},
	{0x00ffffff,0x00ffffff,0x00ffffff}
};

UBYTE farbe[16][2]= {
	{0,1},{0,2},{0,4},{0,6},
	{0,8},{1,10},{2,12},{3,12},
	{4,12},{5,12},{6,12},{7,12},
	{8,12},{9,12},{10,12},{11,12}
	};

UBYTE Palette[13]= {1,2,3,4,5,6,7,8,9,10,11,12,13};

typedef struct ann_struct {
int            bit;
int            x;
struct BitMap  *pixmap;
} ann_struct;


ann_struct ann_tbl[] = {
	{ ANN_LEFT, 16 },
	{ ANN_RIGHT, 39 },
	{ ANN_ALPHA, 63 },
	{ ANN_BATTERY, 85 },
	{ ANN_BUSY, 109 },
	{ ANN_IO, 132 },
	{ 0 }
	};

ann_struct ann_tbl_big[] = {
	{ ANN_LEFT, 36 },
	{ ANN_RIGHT, 81 },
	{ ANN_ALPHA, 126 },
	{ ANN_BATTERY, 171 },
	{ ANN_BUSY, 216 },
	{ ANN_IO, 261 },
	{ 0 }
};

UBYTE nibbles[16] = {
	0x00, /* ---- */
	0x80, /* *--- */
	0x40, /* -*-- */
	0xc0, /* **-- */
	0x20, /* --*- */
	0xa0, /* *-*- */
	0x60, /* -**- */
	0xe0, /* ***- */
	0x10, /* ---* */
	0x90, /* *--* */
	0x50, /* -*-* */
	0xd0, /* **-* */
	0x30, /* --** */
	0xb0, /* *-** */
	0x70, /* -*** */
	0xf0, /* **** */
	};

UBYTE nibbles_ch[16][4] = {
	{0x00,0x00,0x00,0x00}, /* ---- */
	{0x01,0x00,0x00,0x00}, /* *--- */
	{0x00,0x01,0x00,0x00}, /* -*-- */
	{0x01,0x01,0x00,0x00}, /* **-- */
	{0x00,0x00,0x01,0x00}, /* --*- */
	{0x01,0x00,0x01,0x00}, /* *-*- */
	{0x00,0x01,0x01,0x00}, /* -**- */
	{0x01,0x01,0x01,0x00}, /* ***- */
	{0x00,0x00,0x00,0x01}, /* ---* */
	{0x01,0x00,0x00,0x01}, /* *--* */
	{0x00,0x01,0x00,0x01}, /* -*-* */
	{0x01,0x01,0x00,0x01}, /* **-* */
	{0x00,0x00,0x01,0x01}, /* --** */
	{0x01,0x00,0x01,0x01}, /* *-** */
	{0x00,0x01,0x01,0x01}, /* -*** */
	{0x01,0x01,0x01,0x01}, /* **** */
	};

UBYTE nibbles_big[16][2] =
{
	{ 0x00, 0x00 },	/* ---- */
	{ 0xc0, 0xc0 },	/* *--- */
	{ 0x30, 0x30 },	/* -*-- */
	{ 0xf0, 0xf0 },	/* **-- */
	{ 0x0c, 0x0c },	/* --*- */
	{ 0xcc, 0xcc },	/* *-*- */
	{ 0x3c, 0x3c },	/* -**- */
	{ 0xfc, 0xfc },	/* ***- */
	{ 0x03, 0x03 },	/* ---* */
	{ 0xc3, 0xc3 },	/* *--* */
	{ 0x33, 0x33 },	/* -*-* */
	{ 0xf3, 0xf3 },	/* **-* */
	{ 0x0f, 0x0f },	/* --** */
	{ 0xcf, 0xcf },	/* *-** */
	{ 0x3f, 0x3f },	/* -*** */
	{ 0xff, 0xff }	/* **** */
};

UBYTE nibbles_big_ch[16][16] = {
	{ 0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/* ---- */
	 0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00 },
	{ 0x01,0x01,0x00,0x00,  0x00,0x00,0x00,0x00,	/* *--- */
	 0x01,0x01,0x00,0x00,  0x00,0x00,0x00,0x00 },
	{ 0x00,0x00,0x01,0x01,  0x00,0x00,0x00,0x00,	/* -*-- */
	 0x00,0x00,0x01,0x01,  0x00,0x00,0x00,0x00 },
	{ 0x01,0x01,0x01,0x01,  0x00,0x00,0x00,0x00,	/* **-- */
	 0x01,0x01,0x01,0x01,  0x00,0x00,0x00,0x00 },
	{ 0x00,0x00,0x00,0x00,  0x01,0x01,0x00,0x00,	/* --*- */
	 0x00,0x00,0x00,0x00,  0x01,0x01,0x00,0x00 },
	{ 0x01,0x01,0x00,0x00,  0x01,0x01,0x00,0x00,	/* *-*- */
	 0x01,0x01,0x00,0x00,  0x01,0x01,0x00,0x00 },
	{ 0x00,0x00,0x01,0x01,  0x01,0x01,0x00,0x00,	/* -**- */
	 0x00,0x00,0x01,0x01,  0x01,0x01,0x00,0x00 },
	{ 0x01,0x01,0x01,0x01,  0x01,0x01,0x00,0x00,	/* ***- */
	 0x01,0x01,0x01,0x01,  0x01,0x01,0x00,0x00 },
	{ 0x00,0x00,0x00,0x00,  0x00,0x00,0x01,0x01,	/* ---* */
	 0x00,0x00,0x00,0x00,  0x00,0x00,0x01,0x01 },
	{ 0x01,0x01,0x00,0x00,  0x00,0x00,0x01,0x01,	/* *--* */
	 0x01,0x01,0x00,0x00,  0x00,0x00,0x01,0x01 },
	{ 0x00,0x00,0x01,0x01,  0x00,0x00,0x01,0x01,	/* -*-* */
	 0x00,0x00,0x01,0x01,  0x00,0x00,0x01,0x01 },
	{ 0x01,0x01,0x01,0x01,  0x00,0x00,0x01,0x01,	/* **-* */
	 0x01,0x01,0x01,0x01,  0x00,0x00,0x01,0x01 },
	{ 0x00,0x00,0x00,0x00,  0x01,0x01,0x01,0x01,	/* --** */
	 0x00,0x00,0x00,0x00,  0x01,0x01,0x01,0x01 },
	{ 0x01,0x01,0x00,0x00,  0x01,0x01,0x01,0x01,	/* *-** */
	 0x01,0x01,0x00,0x00,  0x01,0x01,0x01,0x01 },
	{ 0x00,0x00,0x01,0x01,  0x01,0x01,0x01,0x01,	/* -*** */
	 0x00,0x00,0x01,0x01,  0x01,0x01,0x01,0x01 },
	{ 0x01,0x01,0x01,0x01,  0x01,0x01,0x01,0x01,	/* **** */
	 0x01,0x01,0x01,0x01,  0x01,0x01,0x01,0x01 }
};

static int menu_x[272]={
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,
	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
	18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,
	};

static int menu_y[272]={
	56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
	56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,
	57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
	57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,
	58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,
	58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,
	59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,
	59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,
	60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
	60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
	61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
	61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,
	62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,
	62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,
	63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,
	63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63
	};

struct BitMap *nibble_maps[16];
struct BitMap *empty;
unsigned char *disp_buf;
unsigned char *db;
static int last_annunc_state = -1;
unsigned char	display_on;
long			display_disp_start;
long			display_disp_end;
char			display_offset;
char			disp_offset;
int				display_lines;
int				display_nibs_per_line;
unsigned char	display_contrast;
long			display_menu_start;
long			display_menu_end;
unsigned char	display_annunc;
int sx,sy,oy,ox,ay,allocbm=0;
int column[33];

void	(*draw_nibble) (int c, int r, unsigned char val);
void	(*draw_menu_nibble) (int c, int r, unsigned char val);
void	(*draw_annunc) (void);


/************************************************************/
void AllocatePens()
{
int i;

for(i=0; i<13; i++) {
	Palette[i] = (UBYTE)(ObtainBestPenA(scr->ViewPort.ColorMap,HP_Colors[i].r,HP_Colors[i].g,HP_Colors[i].b,NULL));
	}
allocpens=1;
}

/************************************************************/
void FreePens()
{
int i;

for(i=0; i<13; i++) ReleasePen(scr->ViewPort.ColorMap,Palette[i]);
}

/***********************************************************************/
inline void redraw_display(void)
{
CopyMemQuick(db,disp_buf, ALL_DISP);
update_display();
}

/************************************************************/
inline void adjust_contrast(int contrast)
{
UBYTE *ptr;
UWORD bpr;
UBYTE Color[2];
int c,i,k;

c=contrast-9;
for (i=0;i<16;i++) {
	Color[0]=Palette[farbe[c][1]];
	Color[1]=Palette[farbe[c][0]];
	if (double_res) {
		if (Chunky) {
			ptr=nibble_maps[i]->Planes[0];
			bpr=GetCyberMapAttr(nibble_maps[i],CYBRMATTR_XMOD);
			for (k=0;k<8;k++) 
				if (nibbles_big_ch[i][k]) *(ptr++)=Color[0];
				else *(ptr++)=Color[1];
			ptr+=bpr-8;
			for (k=8;k<16;k++)
				if (nibbles_big_ch[i][k]) *(ptr++)=Color[0];
				else *(ptr++)=Color[1];
			}
		else {
			bpr=nibble_maps[i]->BytesPerRow;
			for (k=0;k<(bm->Depth);k++) {
				ptr=nibble_maps[i]->Planes[k];
				if (Color[0] & 0x1) {
					*ptr=nibbles_big[i][0];
					ptr+=bpr;
					*ptr=nibbles_big[i][1];
					}
				else {
					if (Color[1] & 0x1) {
						*ptr=~nibbles_big[i][0];
						ptr+=bpr;
						*ptr=~nibbles_big[i][1];
						}
					else {
						*ptr=0x00;
						ptr+=bpr;
						*ptr=0x00;
						}
					}
				Color[0]>>=1;
				Color[1]>>=1;
				}
			}
		}
	else {
		if (Chunky) {
			ptr=nibble_maps[i]->Planes[0];
			for (k=0;k<4;k++) {
				if (nibbles_ch[i][k]) *(ptr++)=Color[0];
				else *(ptr++)=Color[1];
				}
			}
		else 
			for (k=0;k<(bm->Depth);k++) {
				ptr=nibble_maps[i]->Planes[k];
				if (Color[0] & 0x1) *ptr=nibbles[i];
				else {
					if (Color[1] & 0x1) *ptr=~nibbles[i];
					else *ptr=0x00;
					}
				Color[0]>>=1;
				Color[1]>>=1;
				}
			}
	}
redraw_display();
}

/***********************************************************************/
void init_nibble_maps(void)
{
int i,j;
UBYTE *ptr;
UWORD bpr;

for (i = 0; i < 16; i++) {
	if (double_res) {
		nibble_maps[i]=(struct BitMap *)AllocBitMap((ULONG)8,(ULONG)2,(ULONG)bm->Depth,BMF_CLEAR | BMF_MINPLANES,bm);
		if (Chunky) {
			ptr=nibble_maps[i]->Planes[0];
			bpr=GetCyberMapAttr(nibble_maps[i],CYBRMATTR_XMOD);
			for (j=0;j<8;j++) *(ptr++)=nibbles_big_ch[i][j];
			ptr+=bpr-8;
			for (j=8;j<16;j++) *(ptr++)=nibbles_big_ch[i][j];
			}
		else {
			ptr=nibble_maps[i]->Planes[0];
			bpr=nibble_maps[i]->BytesPerRow;
			*ptr=nibbles_big[i][0];
			ptr+=bpr;
			*ptr=nibbles_big[i][1];
			}
		}
	else {
		nibble_maps[i]=(struct BitMap *)AllocBitMap((ULONG)4,(ULONG)1,(ULONG)bm->Depth,BMF_CLEAR | BMF_MINPLANES,bm);
		if (Chunky) {
			ptr=nibble_maps[i]->Planes[0];
			for (j=0;j<4;j++) {
				*(ptr++)=nibbles_ch[i][j];
				}
			}
		else {
			ptr=nibble_maps[i]->Planes[0];
			*ptr=nibbles[i];
			}
		}
	}
}

/***********************************************************************/
void init_annunc(void)
{
int i,j,k;
UBYTE *ptr,*dat;
UWORD bpr;

ay=offy+8;
if (double_res) {
 	for (i=0;i<6;i++) {
		ann_tbl_big[i].pixmap=(struct BitMap *)AllocBitMap((ULONG)16,(ULONG)12,(ULONG)bm->Depth,BMF_CLEAR | BMF_MINPLANES,bm);
		ptr=ann_tbl_big[i].pixmap->Planes[0];
		if (Chunky) {
			bpr=GetCyberMapAttr(ann_tbl_big[i].pixmap,CYBRMATTR_XMOD);
			for(j=0;j<12;j++) {
				dat=ann_bits_big_ch[i][j];
				for (k=0;k<16;k++) *(ptr++)=*(dat++);
				*ptr+=bpr-16;
				}
			}
		else {
			dat=ann_bits_big[i];
			bpr=ann_tbl_big[i].pixmap->BytesPerRow;
			for (j=0;j<12;j++) {
				*(ptr++)=*(dat++);
				*ptr=*(dat++);
				ptr+=bpr-1;
				}
			}
		}
	empty=(struct BitMap *)AllocBitMap((ULONG)16,(ULONG)12,(ULONG)bm->Depth,BMF_CLEAR | BMF_MINPLANES,bm);
	}
else {
	for (i=0;i<6;i++) {
		ann_tbl[i].pixmap=(struct BitMap *)AllocBitMap((ULONG)9,(ULONG)7,(ULONG)bm->Depth,BMF_CLEAR | BMF_MINPLANES,bm);
		ptr=ann_tbl[i].pixmap->Planes[0];
		if (Chunky) {
			bpr=GetCyberMapAttr(ann_tbl[i].pixmap,CYBRMATTR_XMOD);
			for (j=0;j<7;j++) {
				dat=ann_bits_ch[i][j];
				for (k=0;k<9;k++) *(ptr++)=*(dat++);
				ptr+=bpr-9;
				}
			}
		else {
			bpr=ann_tbl_big[i].pixmap->BytesPerRow;
			dat=ann_bits[i];
			for (j=0;j<7;j++) {
				*(ptr++)=*(dat++);
				*ptr=*(dat++);
				ptr+=bpr-1;
				}
			}
		}
	empty=(struct BitMap *)AllocBitMap((ULONG)9,(ULONG)7,(ULONG)bm->Depth,BMF_CLEAR | BMF_MINPLANES,bm);
	}
}

/***********************************************************************/
static void draw_annunc_small(void)
{
int i;

if (display_annunc == last_annunc_state) return;
last_annunc_state = display_annunc;
for (i = 0; ann_tbl[i].bit; i++) {
	if ((ann_tbl[i].bit & display_annunc) == ann_tbl[i].bit)
		BltBitMapRastPort(ann_tbl[i].pixmap,(WORD)0,(WORD)0,rp,(WORD)ann_tbl[i].x+offx,ay,9,7,(UBYTE)0xC0);
	else
		BltBitMapRastPort(empty,(WORD)0,(WORD)0,rp,(WORD)ann_tbl[i].x+offx,ay,9,7,(UBYTE)0xC0);  
	}
}

/***********************************************************************/
static void draw_annunc_big(void)
{
int i;

if (display_annunc == last_annunc_state) return;
last_annunc_state = display_annunc;
for (i = 0; ann_tbl_big[i].bit; i++) {
	if ((ann_tbl_big[i].bit & display_annunc) == ann_tbl_big[i].bit)
		BltBitMapRastPort(ann_tbl_big[i].pixmap,(WORD)0,(WORD)0,rp,(WORD)ann_tbl_big[i].x+offx,ay,16,12,(UBYTE)0xC0);
	else
		BltBitMapRastPort(empty,(WORD)0,(WORD)0,rp,(WORD)ann_tbl_big[i].x+offx,ay,16,12,(UBYTE)0xC0);  
	}
}

/***********************************************************************/
static void draw_nibble_small(int c, int r, unsigned char val)
{
BltBitMapRastPort(nibble_maps[val],0,0,rp,column[c]-disp_offset,r+oy,sx,sy,0xC0);
}

/***********************************************************************/
static void draw_nibble_big(int c, int r, unsigned char val)
{
BltBitMapRastPort(nibble_maps[val],0,0,rp,column[c]-disp_offset,(r << 1)+oy,sx,sy,0xC0);
}

/***********************************************************************/
static void draw_menu_nibble_small(int c, int r, unsigned char val)
{
BltBitMapRastPort(nibble_maps[val],0,0,rp,column[c],r+oy,sx,sy,0xC0);
}

/***********************************************************************/
static void draw_menu_nibble_big(int c, int r, unsigned char val)
{
BltBitMapRastPort(nibble_maps[val],0,0,rp,column[c],(r << 1)+oy,sx,sy,0xC0);
}

/***********************************************************************/
void init_display(void)
{
int i,j;
unsigned char *mybuf;

if ((disp_buf=(unsigned char *)AllocMem(2*DISP_ROWS*NIBS_PER_BUFFER_ROW,MEMF_CHIP|MEMF_CLEAR))==NULL)
	stirb("Can't allco mem for %s.",11,"disp_buf");
if ((db=(unsigned char *)AllocMem(2*DISP_ROWS*NIBS_PER_BUFFER_ROW,MEMF_CHIP|MEMF_CLEAR))==NULL)
	stirb("Can't allco mem for %s.",11,"db");
display_on = saturn_disp_io >> 3;
display_disp_start = (saturn_disp_addr & 0xffffe);
display_offset = saturn_disp_io & 0x7;
disp_offset = 2 * display_offset;
display_lines = (saturn_line_count & 0x3f)+1;
if (!display_lines) display_lines = 64;
/*disp_lines = 2 * display_lines;
if (disp_lines < 110) disp_lines = 110;*/
if (display_offset > 3)
	display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset+2) & 0xfff;
else
	display_nibs_per_line = (NIBBLES_PER_ROW+saturn_line_offset) & 0xfff;
display_disp_end = display_nibs_per_line * display_lines;
/*
display_menu_start = saturn_menu_addr;
display_menu_end = saturn_menu_addr + 0x110;
*/
display_contrast = saturn_contrast_ctrl;
display_contrast |= ((saturn_disp_test & 0x1) << 4);
display_annunc = saturn_annunc;
/*BltClear(disp_buf, sizeof(disp_buf),0);*/
mybuf=db;
for (i=0;i<DISP_ROWS;i++)
	for (j=0;j<2*NIBS_PER_BUFFER_ROW;j++) {
		*mybuf=0xf0;
		mybuf++;
		}
AllocatePens();
init_nibble_maps();
init_annunc();
allocbm=1;
if (double_res) {
	sx=8;
	sy=2;
	ox=offx+24;
	oy=offy+24;
	}
else {
	sx=4;
	sy=1;
	ox=offx+11;
	oy=offy+19;
	}
if (double_res) {
	draw_nibble = draw_nibble_big;
	draw_menu_nibble = draw_menu_nibble_big;
	draw_annunc = draw_annunc_big;
	for (i=0;i<33;i++) column[i]=(i<<3)+ox;
	}
else {
	draw_nibble = draw_nibble_small;
	draw_menu_nibble = draw_menu_nibble_small;
	draw_annunc = draw_annunc_small;
	for (i=0;i<33;i++) column[i]=(i<<2)+ox;
	}
}

/***********************************************************************/
static inline void draw_row(long addr, int row)
{
int i=NPR,v;
unsigned char *mybuf;
unsigned char rrow[NPR];

read_disp(addr+32,rrow);
mybuf=disp_buf+(row<<6)+32;
while (i--) {
	v=rrow[i];
	if(*mybuf != v) {
		*mybuf=v;
		draw_nibble(i,row,v);
		}
	mybuf--;
	}
}

/***********************************************************************/
void update_display(void)
{
int i, j;
long addr;
static char old_offset = -1;
static int old_lines = -1;

if (display_on) {
	addr = display_disp_start;
	if (display_offset != old_offset) {
		BltClear(disp_buf, display_lines*NIBS_PER_BUFFER_ROW,0);
        old_offset = display_offset;
		}
	if (display_lines != old_lines) {
		CopyMemQuick(db,disp_buf, EIGHT_ROW);
		old_lines = display_lines;
		}
	for (i = 0; i < display_lines; i++) {
		draw_row(addr, i);
		addr += display_nibs_per_line;
		}
	if (i < DISP_ROWS) {
		addr = saturn_menu_addr;
		for (; i < DISP_ROWS; i++) {
			draw_row(addr, i);
			addr += NIBBLES_PER_ROW;
			}
		}
	}
else {
	BltClear(disp_buf, ALL_DISP,0);
	}
}

/**********************************************************************/
inline void disp_draw_nibble(int offset, unsigned char val)
{
int x, y;
unsigned char *mybuf;

x=offset%display_nibs_per_line;
if (x>32) return;
mybuf=disp_buf+x;
if (display_nibs_per_line) {
	y=offset/display_nibs_per_line;
	mybuf+=y << 6;
	if (*mybuf != val) {
		*mybuf=val;
		draw_nibble(x,y,val);
		}
	}
else
	for (y = 0; y < display_lines; y++) {
		if (*mybuf != val) {
			*mybuf =val;
			draw_nibble(x, y, val);
			}
		mybuf+=DISP_ROWS;
		}
}

/***********************************************************************/
inline void menu_draw_nibble(int offset, unsigned char val)
{
int x, y;
unsigned char *mybuf;

x=menu_x[offset];
if (x>32) return;
y=menu_y[offset];
mybuf=disp_buf+x+(y<<6);
if (*mybuf != val) {
	*mybuf = val;
	draw_menu_nibble(x,y,val);
	}
}

/***********************************************************************/
inline void redraw_annunc(void)
{
last_annunc_state = -1;
draw_annunc();
}

/***********************************************************************/
void free_bitmaps()
{
int i;

if (db) FreeMem(db,ALL_DISP);
if (disp_buf) FreeMem(disp_buf,ALL_DISP);
if (allocbm) {
	for (i=0;i<16;i++) FreeBitMap(nibble_maps[i]);
	FreeBitMap(empty);
	if (double_res)
		for (i=0;i<6;i++) FreeBitMap(ann_tbl_big[i].pixmap);
	else
		for (i=0;i<6;i++) FreeBitMap(ann_tbl[i].pixmap);
	}	
}

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