head 1.1; access ; symbols ; locks ; comment @@; 1.1 date 89.04.12.09.46.57; author pkern; state Exp; branches ; next ; desc @@ 1.1 log @Initial revision @ text @/* * screen.mda: * IBM PC screen handling, monochrome display * * 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.pc,v 1.3 89/02/06 16:40:42 pkern Exp $"; #include #include "cterm.h" #include "pc.h" #define BLANK 0x00 #define NORM 0x07 /* video mode parameters */ /* text mode */ unsigned int txt_mode=0x07, txt_addr=0xb000; /* advanced video mode (132 columns) */ unsigned int avm_mode=0, avm_addr=0; /* graphics mode */ unsigned int gfx_mode=0, gfx_addr=0; unsigned int gfx_xres=2, gfx_yres=2, gfx_numclr=1; static union REGS r; static struct SREGS sr; static struct REGPACK rp; static uchar xattr=NORM; /* attribute storage */ static char o_scrn[80 * 24 * 2]; /* screen memory storage */ static int o_xy; /* cursor position memory */ static char far *scrn; /* screen position memory */ static int ncols=0, vmode=0, pgnum=0; /* see init_scr() */ static int o_ncols, o_vmode, o_pgnum; /* cursor types */ static unsigned int crsr_blk, crsr_ul; #define sPOS(a, b) (((b)*ncols+(a))*2) static char *scp; /* general purpose screen pointer */ /* 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 GO_XY(a,b) \ r.h.ah=2; r.h.dh=(b); r.h.dl=(a); crtint; #define CLEAN(n) \ r.x.ax=0x0920; r.x.bx=(pgnum<<8)|NORM; r.x.cx=(n); crtint; /* * init_scr: * try to figure out where the display is * and set our internal variables to reflect it. */ init_scr() { if (vmode < 0) { r.h.ah = 0; r.h.al = txt_mode; crtint; } r.h.ah = 0x0f; /* get video mode */ crtint; ncols = r.h.ah; /* num of cols */ vmode = r.h.al; /* video mode */ pgnum = r.h.bh; /* page number */ r.h.ah = 0x03; /* get cursor mode */ crtint; /* CH: start line, CL: end line */ /* CH | 0x40: slow blink, CH | 0x60: fast blink */ crsr_blk = 0x4000 | r.h.cl; crsr_ul = 0x4000 | ((r.h.cl-1) << 8) | r.h.cl; scrn = (char far *) MK_FP(txt_addr, 0); segread(&sr); return (vmode == txt_mode); } reset_scr() { } 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.dl+1; *yp = r.h.dh+1; } columns(n) int n; { return(ncols); } bkgnd(sw) int sw; { /* nothing yet */ } /* 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; { #ifdef BIOS r.h.ah = 6; r.h.al = n; r.h.bh = NORM; r.h.cl = 0; r.h.ch = min_y-1; r.h.dl = ncols-1; r.h.dh = max_y-1; crtint; #else if (n > max_y-min_y+1) n = max_y-min_y+1; else { char *dst, *src; dst = &scrn[sPOS(0, min_y-1)]; src = &scrn[sPOS(0, min_y+n-1)]; memcpy(dst, src, (max_y-min_y-n+1) * ncols * 2); } scp = &scrn[sPOS(0, max_y-n)]; memset(scp, '\0', n * ncols * 2); #endif } /* 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; { #ifdef BIOS r.h.ah = 7; r.h.al = n; r.h.bh = NORM; r.h.cl = 0; r.h.ch = min_y-1; r.h.dh = ncols-1; r.h.dl = max_y-1; crtint; #else if (n > max_y-min_y+1) n = max_y-min_y+1; else { char *dst, *src; dst = &scrn[sPOS(0, min_y+n-1)]; src = &scrn[sPOS(0, min_y-1)]; memcpy(dst, src, (max_y-min_y-n+1) * ncols * 2); } scp = &scrn[sPOS(0, min_y-1)]; memset(scp, '\0', n * ncols * 2); #endif } /* eol : erase to end of line */ eol_erase(x, y) uchar x, y; { if (x > ncols) return; #ifdef BIOS CLEAN(ncols-(x-1)) #else scp = &scrn[sPOS(x-1, y-1)]; memset(scp, '\0', (ncols-x+1) * 2); #endif } /* * 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; { #ifdef BIOS GO_XY(0, y-1) CLEAN(x) GO_XY(x-1, y-1) #else scp = &scrn[sPOS(0, y-1)]; memset(scp, '\0', x * 2); #endif } /* eos : erase to end of line and to end of screen */ eos_erase(x, y) uchar x, y; { #ifdef BIOS CLEAN((24-y)*ncols + ncols-x+1) #else scp = &scrn[sPOS(x-1, y-1)]; memset(scp, '\0', ((24-y)*ncols + ncols-x+1) * 2); #endif } /* * bos : erase from beginning of screen (home) to cursor pos. */ bos_erase(x, y) uchar x, y; { #ifdef BIOS GO_HOME CLEAN(ncols*(y-1)+x) GO_XY(x-1, y-1) #else scp = scrn; memset(scp, '\0', (ncols*(y-1)+x) * 2); #endif } /* goto head of line, erase line, return to original pos */ line_erase(x, y) uchar x, y; { #ifdef BIOS GO_XY(0, y-1) CLEAN(ncols) GO_XY(x-1, y-1) #else scp = &scrn[sPOS(0, y-1)]; memset(scp, '\0', ncols * 2); #endif } /* erase entire screen (not including status line) */ all_erase(x, y) uchar x, y; { #ifdef BIOS GO_HOME CLEAN(ncols*24) GO_XY(x-1, y-1) #else scp = scrn; memset(scp, '\0', ncols * 24 * 2); #endif } /* * 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; { scrl_down(n, y, max_y, x, y); GO_XY(0, y-1) } /* * 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; { scrl_up(n, y, max_y, x, y); GO_XY(0, y-1) } /* * delete char(s) : * ie. copy 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; { char *p; register uchar yn = y-1; if (x > ncols) return; if (x+n-1 > ncols) n = ncols-x+1; scp = &scrn[sPOS(x-1, yn)]; p = &scrn[sPOS(x+n-1, yn)]; memcpy(scp, p, (ncols-(x+n-1)) * 2); scp = &scrn[sPOS(ncols-n, yn)]; memset(scp, '\0', n * 2); } /* * insert char(s) : * ie. copy rest of line to right and clean out new space(s) */ char_ins(n, x, y) uchar n, x, y; { char *p; register uchar yn = y-1; if (x > ncols) return; if (x+n-1 > ncols) n = ncols-x+1; scp = &scrn[sPOS(x-1, yn)]; p = &scrn[sPOS(x+n-1, yn)]; memcpy(p, scp, (ncols-(x+n-1)) * 2); scp = &scrn[sPOS(x-1, yn)]; memset(scp , '\0', n * 2); } /* * set attributes */ uchar c_norm=7, c_rev=7, c_bold=7; attribs(attr) uchar attr; { xattr = NORM; if (attr & AT_UL) xattr = 0x01; if (attr & AT_BOLD) xattr |= 0x08; if (attr & AT_BLINK) xattr |= 0x80; if (attr & AT_REV) xattr = (xattr & 0x88) | 0x70; } /* * 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.bh = pgnum; r.h.bl = NORM; r.x.cx = ncols * 24; crtint; /* screen of E's */ } /* basic single-char output */ burpc(c, x, y) int c, x, y; { #ifdef BIOS r.h.ah = 0x09; r.h.al = c; r.h.bh = pgnum; r.h.bl = xattr; r.x.cx = 1; crtint; #else scp = &scrn[sPOS(x-1, y-1)]; *scp++ = c; *scp++ = xattr; if (!*++scp) *scp = NORM; #endif GO_XY(x, y-1) } /* sound bell/horn/whistle/whatever */ beep(x, y) int x, y; { /* r.x.ax = 0x0e07; r.x.bx = (pgnum << 8); crtint; */ /* honk(0x533, 64); /* normal 1000 Hz bell */ /* mildly fancy honk(0x333, 32); honk(0x533, 32); honk(0x733, 32); */ #ifdef PLAY /* getting fancier ... */ play("g3.24,d3.24,g3.24,d3.24,g3.24"); #else /* default */ honk(2915, 64); /* middle C (approx. 440 Hz) */ #endif } /* insert mode burpc() */ /* move line right, deposit char */ insurpc(c, x, y) int c, x, y; { char_ins(1, x, y); burpc(c, x, y); } /* output string at x,y with attr */ burps(s, x, y, at) char *s; uchar x, y, at; { int c; uchar xn = x, yn = y; c = xattr; attribs(at); #ifdef BIOS GO_XY(xn-1, yn-1) while (*s) { burpc(*s++, xn++, yn); if (xn == ncols) { xn = 1; if (yn < 24) yn++; } } #else scp = &scrn[sPOS(x-1, y-1)]; while (*s) { *scp++ = *s++; *scp++ = xattr; } #endif GO_XY(x-1, y-1); xattr = c; } /* set cursor type */ curs_type(sw) uchar sw; { r.h.ah = 1; r.x.cx = (sw) ? crsr_blk : crsr_ul; crtint; } /* save screen image & cursor position */ save_scr() { register int n; register char *os, *s; r.h.ah = 3; crtint; o_xy = r.x.dx; o_ncols = ncols; n = ncols * 24 * 2; s = scrn; os = o_scrn; /* while (n--) *os++ = *s++; */ memcpy(os, s, n); } /* restore screen image & cursor position */ #define osPOS(a, b) (((b)*o_ncols+(a))*2) #define MIN(a,b) (((a)<(b))?(a):(b)) restore_scr() { register int n; register char *os, *s; n = ncols * 24 * 2; s = scrn; os = o_scrn; /* while (n--) *s++ = *os++; */ memcpy(s, os, n); r.h.ah = 2; r.x.dx = o_xy; crtint; } /* 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 > 24) return(-1); j = sPOS(0, lnum-1); /* first column */ n = sPOS(ncols-1, lnum-1); /* last column */ /* find last non-blank char in line */ for (; j < n; n-=2) if (o_scrn[n] != NUL && o_scrn[n] != ' ') { n += 2; break; } /* save text to buf */ for (i=0; i < siz && j < n; i++, j+=2) 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; { int i=0, c; c = (c_stat) ? 0x70 : 0; /* reverse video or blank */ #ifdef BIOS burps(s, 1, 25, c); #else scp = &scrn[sPOS(0, 24)]; while (*s && i++ < ncols) { *scp++ = *s++; *scp++ = c; } while (i < ncols) { *scp++ = ' '; *scp++ = c; i++; } #endif /* PC/AT * rp.r_ax = 0x1300; * rp.r_bx = (pgnum << 8) | c; * i = strlen(s); * rp.r_cx = (i > ncols-1) ? ncols-1 : i; * rp.r_dx = 0x1800; * rp.r_es = sr.ds; * rp.r_si = (unsigned int)s; * intr(CRT_INT, &rp); */ GO_XY(x-1, y-1) } /* delay for n milliseconds */ dsleep(n) unsigned int n; { #ifdef notdef /* #ifdef PCAT */ unsigned long m; m = n * 1000; r.h.ah = 86; r.x.cx = m >> 16; r.x.dx = m & 0xffff; int86(0x15, &r, &r); #else unsigned int x; while(n--) for (x=0x400; x; x--) ; /* ... just a guess */ #endif } /* clear screen & home cursor */ clr_home() { GO_HOME #ifdef BIOS CLEAN(ncols * 25) #else scp = scrn; memset(scp, '\0', ncols * 25 * 2); #endif } /* dburp -- put debug message on status line */ dburp(s) char *s; { uchar x, y; xypos(&x, &y); sturp(s, x, y); } /* * honk: sound the horn */ #define TimerCtl 0x43 #define Timer2Cnt 0x42 #define BPort 0x61 honk(tdiv, n) unsigned int tdiv, n; { unsigned char bsav; register unsigned int i; register unsigned char c, x; c = tdiv >> 8; x = tdiv & 0xff; outportb(TimerCtl, 0xb6); /* select timer 2 */ outportb(Timer2Cnt, x); /* timer 2 counter lsb */ outportb(Timer2Cnt, c); /* timer 2 counter msb */ c = inportb(BPort); /* save 8255 port b setting */ bsav = c; c |= 3; outportb(BPort, c); /* turn speaker on */ while (n--) for(x=1; x; x++) ; outportb(BPort, bsav); /* restore 8255 port */ } #ifdef PLAY #define sqrt_2 1.059463994 /* 12th root of 2 */ /* * 12 notes/octave; c d# d e# e f g# g a# a b# b * 0 1 2 3 4 5 6 7 8 9 10 11 */ static int notes[7] = { 9, 11, 0, 2, 4, 5, 7}; /* a b c d e f g */ play(p) char *p; { int note, octv, tlen; float freq; long clk; tlen = 10; /* expecting: n[#]o.l{,n[#]o.l} n == note [a-g], [#] == optional sharp, o == octave [0-..], l == duration [1-..] */ while (*p) { freq = 55.0; /* low "C" == 55 Hz */ clk = 1283000; /* PC/AT speaker clock speed */ octv = 0; note = notes[*p - 'a']; if (*++p == '#') { p++; if (note) note--; else { /* c# */ octv = 1; note = notes['g']; } } octv += atoi(p); while (*++p != '.') ; tlen = atoi(++p); while (*p && *p++ != ',') ; for (; octv; octv--) freq *= 2; for (; note; note--) freq *= sqrt_2; note = clk/freq; honk(note, tlen); } } #endif /* PLAY */ /* IBM PC graphics nitty-gritty */ init_gfx() { extern uchar interlace, gcolour; extern int gmax_x, gmax_y, gmax_clr; gmax_x = gfx_xres = 2; gmax_y = gfx_yres = 2; gmax_clr = gfx_numclr = 1; gcolour = gmax_clr-1; } /* gfx_erase -- clear or hide the graphics screen */ gfx_erase() { r.h.ah = 0; r.h.al = vmode & 0x7f; crtint; } gfx_colour(n) uchar n; { return(1); } /* gpeek -- get a pixel's colour */ gpeek(x, y) int x, y; { return(1); } /* boink -- light a pixel */ boink(x,y,c) int x, y; uchar c; { /* zilch */ } /* * hline -- only does horizontal lines (union regulations :-) * (called from bline(), should be optimized for speed). */ hline(x,y,n,c) int x; register int y,n; uchar c; { /* zilch */ } /* * vline -- vertical lines only * (again, called from bline(), should be optimized for speed). */ vline(x,y,n,c) int y; register int x,n; uchar c; { /* zilch */ } /* * xrun -- optimize search for runs to colour c in x direction * (called from dofill(), should be quicker that gpeek()-ing each pixel) */ xrun(x, y, c, dir) int x, y, dir; uchar c; { return(x); } @