/* * screen handling routines for TI Professional (including graphics) * * Note: * - it seems necessary to assert the status line after each CLEANing * (a minor annoyance, but if we want to enforce a status line ...) * * Copyright (c) 1989 University of Toronto. All rights reserved. * Anyone may use or copy this software, except that it may not be * sold for profit, that this copyright notice remain intact, and that * credit is given where it is due. The University of Toronto and the * author make no warranty and accept no liability for this software. */ static char rcsid[] = "$Header: screen.ti,v 1.8 89/05/02 16:25:23 pkern Exp $"; #include #include "cterm.h" #include "ti.h" #define BLANK 0x0f /* #define SCR_MEM (0xde000000) /* screen location */ #define SCR_MEM (0xde00) /* screen location segment */ #define L_ATTR *((char far *)0xdf800000) /* attribute latch */ #define CRSR_BLK 0x600c /* slow-blinking block cursor code */ #define CRSR_UL 0x4b0b /* fast-blinking underline cursor */ static union REGS r; static struct SREGS sr; static int xattr=0x0f, o_xattr; /* current attribute storage */ static char o_scrn[SCRSIZE]; /* screen memory storage */ static char o_attr[SCRSIZE]; /* attribute storage */ static int o_xy=-1; /* cursor position memory */ static char far *scrn; /* screen position memory */ uchar g_type=0; /* text colours/intensities */ uchar c_norm=5, c_rev=5, c_bold=7, c_ul=5; static uchar o_norm=5, o_rev=5, o_bold=7, o_ul=5; /* macros for frequently used code */ #define crtint int86(CRT_INT, &r, &r) #define GO_HOME r.h.ah=2; r.x.dx=0; crtint; #define DO_STAT r.h.ah=0x15; r.x.cx=ROWS; crtint; #define GO_XY(a,b) \ r.h.ah=2; r.h.dh=(a); r.h.dl=(b); crtint; #define CLEAN(n) \ r.x.ax=0x0920; r.h.bl=(0x08|c_norm); r.x.cx=(n); \ crtint; L_ATTR = xattr; /* set status region on 25th line */ init_scr() { extern uchar srgn_bot; DO_STAT segread(&sr); attribs(0); srgn_bot = ROWS; } /* eliminate status region, reset attributes */ reset_scr() { r.h.ah = 0x15; r.x.cx = 0; crtint; L_ATTR = BLANK; } curs_xy(x, y) uchar x, y; { GO_XY(x-1, y-1) } xypos(xp, yp) uchar *xp, *yp; { r.h.ah = 3; crtint; *xp = r.h.dh+1; *yp = r.h.dl+1; } columns(n) int n; { GO_HOME CLEAN(80*ROWS) DO_STAT return(80); /* can't do 132 columns on a TI */ } bkgnd(sw) int sw; { /* reverse background not worth the * extra code needed to implement it. */ } /* scroll up n lines between min_y and max_y */ scrl_up(n, min_y, max_y, x, y) uchar n, min_y, max_y, x, y; { r.h.ah = 6; r.h.al = 1; r.h.dh = 0; r.h.dl = min_y-1+n; r.h.bh = 0; r.h.bl = min_y-1; r.h.ch = 80; r.h.cl = max_y - (min_y-1) - n; crtint; GO_XY(0, max_y-n) CLEAN(80 * n) GO_XY(x-1, y-1) DO_STAT } /* scroll down n lines between min_y and max_y */ scrl_down(n, min_y, max_y, x, y) uchar n, min_y, max_y, x, y; { r.h.ah = 7; r.h.al = 1; r.h.dh = 0; r.h.dl = min_y-1; r.h.bh = 0; r.h.bl = min_y-1+n; r.h.ch = 80; r.h.cl = max_y - (min_y-1) - n; crtint; GO_XY(0, min_y-1) CLEAN(80 * n) GO_XY(x-1, y-1) DO_STAT } /* eol : erase to end of line */ eol_erase(x, y) uchar x, y; { if (x > 80) return; CLEAN(80-(x-1)) DO_STAT } /* * bol : erase from beginning of line to cursor pos. * ie. goto head of line, erase chars, return to original pos */ bol_erase(x, y) uchar x, y; { GO_XY(0, y-1) CLEAN(x) GO_XY(x-1, y-1) DO_STAT } /* eos : erase to end of line and to end of screen */ eos_erase(x, y) uchar x, y; { CLEAN( (ROWS-y) * 80 + (80-(x-1)) ) DO_STAT } /* * bos : erase from beginning of screen (home) to cursor pos. * ie. goto head of screen, erase to original pos, return to position */ bos_erase(x, y) uchar x, y; { GO_HOME CLEAN(80 * (y-1) + x) GO_XY(x-1, y-1) DO_STAT } /* goto head of line, erase line, return to original pos */ line_erase(x, y) uchar x, y; { GO_XY(0, y-1) CLEAN(80) GO_XY(x-1, y-1) DO_STAT } /* goto head of screen, erase all, return to pos */ /* could've used AH=0x13 but it also erases the status line */ all_erase(x, y) uchar x, y; { GO_HOME CLEAN(80*ROWS) GO_XY(x-1, y-1) DO_STAT } /* * insert line(s) : * scroll down n lines, goto head of original line, erase empty space */ line_ins(n, x, y, max_y) uchar n, x, y, max_y; { if (y-1+n < max_y) { r.h.ah = 6; r.h.al = 1; r.h.dh = 0; r.h.dl = y-1; r.h.bh = 0; r.h.bl = y-1+n; r.h.ch = 80; r.h.cl = max_y-(y-1)-n; crtint; } else n = max_y - (y-1); GO_XY(0, y-1) CLEAN(80 * n) DO_STAT } /* * delete line(s) : * scroll up n lines, goto new empty line, erase lines, * return to head of original line */ line_del(n, x, y, max_y) uchar n, x, y, max_y; { if (y-1+n < max_y) { r.h.ah = 6; r.h.al = 1; r.h.dh = 0; r.h.dl = y-1+n; r.h.bh = 0; r.h.bl = y-1; r.h.ch = 80; r.h.cl = max_y-(y-1)-n; crtint; } else n = max_y - (y-1); GO_XY(0, max_y-n) CLEAN(80 * n) GO_XY(0, y-1) DO_STAT } /* * delete char(s) : * ie. scroll rest of line to the left, goto line-end, erase n chars * and return to original cursor pos */ char_del(n, x, y) uchar n, x, y; { if (x-1+n < 80) { r.h.ah = 6; r.h.al = 1; r.h.dh = x-1+n; r.h.dl = y-1; r.h.bh = x-1; r.h.bl = y-1; r.h.ch = 80-(x-1)-n; r.h.cl = 1; crtint; } else n = 80-(x-1); GO_XY(80-n, y-1) CLEAN(n) GO_XY(x-1, y-1) DO_STAT } /* * insert char(s) : * ie. scroll rest of line to right and clean out new space(s) */ char_ins(n, x, y) uchar n, x, y; { if (x-1+n < 80) { r.h.ah = 6; r.h.al = 1; r.h.dh = x-1; r.h.dl = y-1; r.h.bh = x-1+n; r.h.bl = y-1; r.h.ch = 80-(x-1)-n; r.h.cl = 1; crtint; } else n = 80-(x-1); CLEAN(n) DO_STAT } /* * set attributes */ attribs(attr) uchar attr; { r.h.ah = 0x16; r.h.bl = 0x08 | c_norm; if (attr & AT_REV) r.h.bl = 0x08 | c_rev; if (attr & AT_BOLD) { r.h.bl = 0x08 | c_bold; attr &= 0x07; } r.h.bl |= (attr << 4); L_ATTR = r.h.bl; xattr = r.h.bl; /* crtint; */ } /* * screen alignment test : * home cursor and write a screen of E's in normal attrib mode. * previous attribs are not forgotten. */ e_screen() { GO_HOME r.h.ah = 0x09; r.h.al = 'E'; r.h.bl = 0x08 | c_norm; /* ordinary attribs */ r.x.cx = 80 * ROWS; crtint; /* screen of E's */ L_ATTR = xattr; DO_STAT } /* basic single-char output */ burpc(c, x, y) int c, x, y; { r.h.ah = 0x0e; r.h.al = c; crtint; } /* insert mode burpc() */ /* move line right, deposit char */ insurpc(c, x, y) int c, x, y; { if (x < 80) { r.h.ah = 6; r.h.al = 1; r.h.bh = x; r.h.bl = y-1; r.h.ch = 80-x; r.h.cl = 1; r.h.dh = x-1; r.h.dl = y-1; crtint; } L_ATTR = xattr; r.h.ah = 0x0e; r.h.al = c; crtint; } /* output string at x,y with attr */ burps(s, x, y, at) char *s; uchar x, y, at; { GO_XY(x-1, y-1) r.h.ah = 0x10; r.h.al = 0x08 | c_norm; if (at & AT_REV) r.h.al = 0x08 | c_rev; if (at & AT_BOLD) { r.h.al = 0x08 | c_bold; at &= 0x07; } r.h.al |= (at << 4); xattr = r.h.al; r.x.bx = (int)s; r.x.cx = strlen(s); r.x.dx = sr.ds; crtint; } /* set cursor type */ curs_type(sw) uchar sw; { r.h.ah = 1; r.x.cx = (sw) ? CRSR_BLK : CRSR_UL; if (sw & 0x80) r.h.ch = 0x20 | (r.h.ch & 0x1f); crtint; } /* save screen image & cursor position */ save_scr() { register int n; register char far *s; register char *os, *ap; register uchar xa, xn; if (o_xy >= 0) return; r.h.ah = 3; crtint; o_xy = r.x.dx; r.h.ah = 0x17; crtint; scrn = (char far *) MK_FP(SCR_MEM, r.x.dx); n = SCRSIZE; s = scrn; os = o_scrn; ap = o_attr; o_xattr = xattr; xn = 0; while (n--) { *os++ = *s++; xa = L_ATTR; if (xa == xn) xa = 0; else xn = xa; *ap++ = xa; } o_norm = c_norm; o_rev = c_rev; o_bold = c_bold; return(o_xy); } /* restore screen image & cursor position */ restore_scr() { uchar c_new; register int n; register char far *s; register char *os, *ap; if (o_xy < 0) return; c_new = (c_norm != o_norm) || (c_rev != o_rev) || (c_bold != o_bold); r.h.ah = 0x17; crtint; scrn = (char far *) MK_FP(SCR_MEM, r.x.dx); n = SCRSIZE; s = scrn; os = o_scrn; ap = o_attr; while (n--) { if (*ap++) { register uchar xa; xa = (*(ap-1)); if (c_new) { register uchar xn; xn = xa & 7; xa &= 0xf8; if (xn == o_norm) xn = c_norm; else if (xn == o_rev) xn = c_rev; else if (xn == o_bold) xn = c_bold; xa |= xn; } L_ATTR = xa; } *s++ = *os++; } r.h.ah = 2; r.x.dx = o_xy; crtint; xattr = o_xattr & 7; o_xattr &= 0xf8; if (xattr == o_norm) xattr = c_norm; else if (xattr == o_rev) xattr = c_rev; else if (xattr == o_bold) xattr = c_bold; xattr |= o_xattr; L_ATTR = xattr; o_xy = -1; } /* save text in line lnum from o_scrn to buf */ scgets(buf, siz, lnum) char buf[]; int siz, lnum; { int i, j, n; if (lnum > ROWS) return(-1); j = (lnum-1) * 80; /* first column */ n = (lnum*80) - 1; /* last column */ /* find last non-blank char in line */ for (; j < n; n--) if (o_scrn[n] != NUL && o_scrn[n] != ' ') { n++; break; } /* save text to buf */ for (i=0; i < siz && j < n; i++, j++) buf[i] = o_scrn[j]; buf[i] = NUL; return(i); } /* write string to status line */ uchar c_stat=3; sturp(s, x, y) char *s; int x, y; { GO_XY(0, ROWS) r.h.ah = 0x10; r.h.al = (c_stat) ? (0x18 | c_stat) : 0; r.x.bx = (int)s; r.x.cx = strlen(s); r.x.dx = sr.ds; crtint; GO_XY(x-1, y-1) L_ATTR = xattr; } /* delay for n milliseconds */ dsleep(n) unsigned int n; { r.h.ah = 5; r.x.cx = n; int86(0x48, &r, &r); } /* sound bell/horn/whistle/whatever */ beep(x, y) int x, y; { r.h.ah = 0x0e; r.h.al = 7; /* ^G */ crtint; } /* bios -- Clear Text Screen And Home the Cursor */ clr_home() { r.h.ah = 0x13; crtint; } /* dburp -- put debug message on status line */ dburp(s) char *s; { uchar x, y; xypos(&x, &y); sturp(s, x, y); } /* erase graphics screen */ gfx_erase() { r.h.ah = 0x14; crtint; } /* TI Pro graphics nitty-gritty */ /* graphics screen limits */ #define GMAX_X 720 #define GMAX_Y 300 /* graphics palette attribute latches (write-only) */ #define L_BLU *((char far *)0xdf000010) #define L_GRN *((char far *)0xdf000020) #define L_RED *((char far *)0xdf000030) /* our own latch memory since latches are write-only */ static uchar l_blu=0xAA, l_red=0xCC, l_grn=0xF0; /* sync our latches with the real ones */ #define L_SYNC L_BLU=l_blu; L_RED=l_red; L_GRN=l_grn; /* * l_tab: * latch table for possible graphics plane config * The following l_tab arrangement makes green (intensity 4) the * "most significant colour" and blue (intensity 1) the "least * significant colour" with red (intensity 2) in between. * If there is only 1 bit-plane present, the available colours * will be green and black. With 2 bit-planes the available * colours will be yellow (intensity 6), green, red and black. * With all 3 bit-planes present, blue is finally available so all * 8 colours/intensities can be used (black is a colour, isn't it? :-) * See also "#define ADJUST" */ static uchar l_tab[24] = { /* Grn Red Blu */ 0xFF, 0xFF, 0xFF, /* - - - */ 0xFE, 0x00, 0x00, /* - - A */ 0xFE, 0x00, 0x00, /* - B - */ 0xF0, 0xEE, 0x00, /* - B A */ 0xFE, 0x00, 0x00, /* C - - */ 0xFC, 0xFA, 0x00, /* C - A */ 0xF0, 0xEE, 0x00, /* C B - */ 0xF0, 0xCC, 0xAA /* C B A */ }; static uchar cnum=3, cmap=7; /* # of bit-planes, which are installed */ /* * ADJUST: adjust colour if some bit-planes are missing */ /* quick & dirty: assumes has only 1 or has all 3 bit-planes */ #define ADJUST(a) if (cnum==1 && a) a=cmap; /* #define ADJUST(a) \ switch (cnum) { \ case 1: if (a) a = cmap; break; \ case 2: a = (a+1)>>1; \ if (~cmap & 2) a = (a&2)<<1 | (a&1); \ else if (~cmap & 1) a = a << 1; \ break; \ } /* */ /* graphics bank (bit-plane) access */ #define GBa(m) *((unsigned int far *)0xc0000000+m) #define GBb(m) *((unsigned int far *)0xc8000000+m) #define GBc(m) *((unsigned int far *)0xd0000000+m) #define GBOFS(a,b) (((b)*46)+((a)/16)) /* x,y byte offset */ #define GMASK(a) (0x8000 >> ((a)%16)) /* bit offset for x */ static int o_gclr = -1; init_gfx() { int i, n = 0; extern unsigned int sysconfig; extern uchar interlace, gcolour; extern int gmax_x, gmax_y, gmax_clr; L_BLU = L_RED = L_GRN = 0; gmax_x = GMAX_X; gmax_y = GMAX_Y; cmap = (sysconfig >> 12) & 7; /* count number of installed gfx banks (max 3) */ for (i = cnum = 0; i < 3; i++) cnum += (cmap >> i) & 1; gmax_clr = 1 << cnum; i = cmap * 3; l_grn = l_tab[i]; l_red = l_tab[i+1]; l_blu = l_tab[i+2]; /* C B A --> B C A (ie. map banks to colours) */ cmap = ((cmap & 4)>>1) | ((cmap & 2)<<1) | (cmap & 1); if (interlace) { if (o_gclr < 0) o_gclr = gmax_clr-1 ; gcolour = o_gclr; L_SYNC } } gfx_colour(n) uchar n; { ADJUST(n) o_gclr = n; return(n); } static unsigned int ofs, msk; #define BOINK(a) \ if (a & 1) GBa(ofs) |= msk; else GBa(ofs) &= ~msk; \ if (a & 4) GBb(ofs) |= msk; else GBb(ofs) &= ~msk; \ if (a & 2) GBc(ofs) |= msk; else GBc(ofs) &= ~msk; #define xBOINK(a) \ if (a & 1) GBa(ofs) ^= msk; \ if (a & 4) GBb(ofs) ^= msk; \ if (a & 2) GBc(ofs) ^= msk; #define GPEEK \ (((GBa(ofs) & msk) == msk) \ | (((GBc(ofs) & msk) == msk) << 1) \ | (((GBb(ofs) & msk) == msk) << 2)) /* gpeek -- get a pixel's colour */ gpeek(x, y) int x, y; { uchar c; msk = GMASK(x); ofs = GBOFS(x,y); /* * c = ((GBa(ofs) & msk) == msk); * c |= ((GBc(ofs) & msk) == msk) << 1; * c |= ((GBb(ofs) & msk) == msk) << 2; */ c = GPEEK; ADJUST(c) return(c); } /* boink -- light a pixel */ boink(x,y,c) int x, y; register uchar c; { msk = GMASK(x); ofs = GBOFS(x,y); BOINK(c) } /* * hline -- only does horizontal lines (union regulations :-) * use solid(ie. multi bit) masks and increment the offset */ hline(x,y,n,c) int x,y,n; uchar c; { if (n < 0) { n = -n; x -= n; if (x < 0) { n += x; x = 0; } } msk = 0xffff >> (x%16); /* make mask go to end of 16bit word */ for(ofs=GBOFS(x,y); ofs < GBOFS(x+n, y); ofs++) { BOINK(c) msk = 0xffff; /* ie. solid while between end-points */ } msk &= ~(0xffff >> ((x+n)%16)); /* remainder word mask */ BOINK(c) } /* * vline -- vertical lines only * get bit mask once then move it up or down * by changing only the offset +/- 46. */ vline(x,y,n,c) int x,y,n; uchar c; { if (n < 0) { n = -n; y -= n; if (y < 0) { n += y; y = 0; } } msk = GMASK(x); ofs = GBOFS(x,y); for (; n; n--, ofs+=46) { BOINK(c) } } /* xrun -- optimize search for runs in x direction */ xrun(x, y, c, dir) int x, y, dir; uchar c; { uchar cx; unsigned int ba, bb, bc; msk = GMASK(x); ofs = GBOFS(x,y); ba = GBa(ofs); bb = GBb(ofs); bc = GBc(ofs); while (0 <= x && x < GMAX_X) { cx = ((ba & msk) == msk) \ | (((bc & msk) == msk) << 1)\ | (((bb & msk) == msk) << 2); if (c == cx) break; x += dir; msk = GMASK(x); if (((dir > 0) && (x%16) == 0) || ((dir < 0) && (x%16) == 15)) { ofs = GBOFS(x,y); ba = GBa(ofs); bb = GBb(ofs); bc = GBc(ofs); } } if (c == cx) x -= dir; if (x < 0) return(0); if (x >= GMAX_X) return(GMAX_X-1); return(x); }