/* PCX.c - Graphic Routines that operate on PCX pictures */ #include #include "lib.h" #include "pcx.h" int pcx_init(); int pcx_clear(); int pcx_set_point(); int pcx_clr_point(); int pcx_xor_point(); int pcx_write_row(); int pcx_select_plane(); int pcx_set_palette(); int pcx_mode(); int movmem(); int pokeb(); int peekb(); int pcx_get_point(); static int (*pcx_func[])() = { pcx_init, pcx_clear, pcx_set_point, pcx_clr_point, pcx_xor_point, pcx_get_point, pcx_write_row, pcx_select_plane, pcx_set_palette,pcx_mode, movmem, peekb, pokeb }; PCXPIC *pcx_cpic; /* current picture */ static int cplane; /* current plane */ int pcx_md; /* 1 if CGA-type picture, 0 for HERC/EGA */ int pcx_init() { movmem( pcx_func, vgr_func, sizeof(vgr_func) ); VGR_NBPL = VGR_HRES = VGR_VRES = VGR_NCOLORS = cplane = 0; if ( pcx_cpic ) { VGR_HRES = pcx_cpic->hdr.hres; VGR_VRES = pcx_cpic->hdr.vres; VGR_NBPL = pcx_cpic->hdr.bpl; VGR_NCOLORS = pcx_cpic->hdr.bpp > 1 ? 0x01 << pcx_cpic->hdr.bpp : 0x01 << pcx_cpic->hdr.nplanes; }; return OK; } int pcx_select_plane( plane ) int plane; { return cplane = plane & 0x03; } int pcx_write_row( row, prow, nbytes ) int nbytes, row; char *prow; { int i; i = pcx_cpic->hdr.hres / 8; movmem( prow, (pcx_cpic->rows[cplane][row]), nbytes <= i ? nbytes : i ); } int pcx_clear() { int plane, row, nplanes, nrows, bytes; nplanes = pcx_cpic->hdr.nplanes; nrows = pcx_cpic->hdr.y2 - pcx_cpic->hdr.y1 +1; bytes = pcx_cpic->hdr.bpl; for ( plane=0; plane < nplanes; plane ++ ) for ( row=0; row < bytes; row++ ) setmem( (pcx_cpic->rows[plane][row]), bytes, 0 ); } int pcx_mode( m ) int m; { switch ( m ) { case MODE_APA0: /* 640x350x16 */ case MODE_APA1: /* 720x348x02 */ case MODE_APA2: /* 640x200x02 */ /* all these modes save color information 1 bit per plane. */ pcx_md = 0; break; case MODE_APA3: /* 320x200x04 */ /* this mode puts two bits per pixel into the same plane. */ pcx_md = 1; break; default: /* invalid! */ return ERROR; }; return OK; } int pcx_xor_point( x, y, color ) int x, y, color; { return pcx_set_point( x, y, pcx_get_point( x, y ) ^ color ); } int pcx_clr_point( x, y ) int x, y; { return pcx_set_point( x, y, 0 ); } int pcx_set_point( x, y, color ) int x, y, color; { register unsigned char *p; unsigned char plane, b, o, mask; if ( pcx_md ) { o = (x & 3) << 1; p = (unsigned char *)pcx_cpic->rows[0][y] + (x>>2); *p = (*p & ~(0xc0 >> o)) | ((color & 0x03) << (6-o)); return OK; }; o = x >> 3; b = (unsigned int)0x80 >> (x & 0x07); for ( mask=1,plane=0; plane < pcx_cpic->hdr.nplanes; plane++, mask<<=1 ) { p = (unsigned char *)pcx_cpic->rows[plane][y] + o; if ( color & mask ) *p |= b; else *p &= ~b; }; return OK; } int pcx_get_point( x, y ) int x, y; { unsigned char plane, b, o, color; if ( pcx_md ) { b = (x & 3) << 1; return ( pcx_cpic->rows[0][y][x>>2] & (0xc0 >> b) ) >> (6-b); }; o = x >> 3; b = (unsigned int)0x80 >> (x & 0x07); for ( color=plane=0; plane < pcx_cpic->hdr.nplanes; plane++ ) color |= !!(pcx_cpic->rows[plane][y][o] & b) << plane; return color; } /* PCX Palette Settings. */ int pcx_set_palette( reg, red, green, blue ) unsigned char reg, red, green, blue; { if ( pcx_md ) { pcx_cpic->hdr.triple[reg].red = red; return OK; }; /* why do we multiply by 85? */ pcx_cpic->hdr.triple[reg].red = red * 85; pcx_cpic->hdr.triple[reg].green = green * 85; pcx_cpic->hdr.triple[reg].blue = blue * 85; return OK; } PCXPIC *pcx_init_pic( hres, vres, nplanes ) unsigned int hres, vres, nplanes; { int y, p, bpl; PCXPIC *pic; char *calloc(); static TRIPLET ega_pal[] = { /* copied from a */ 0x00, 0x00, 0x00, /* PBRUSH picture file */ 0x00, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0x55, 0xff, 0x55, 0xff, 0x55, 0x55, 0xff, 0xff, 0xff, 0x55, 0x55, 0xff, 0x55, 0xff, 0xff, 0xff, 0x55, 0xff, 0xff, 0xff }; static TRIPLET cga_pal[] = { 0,0,0, 255,0,0, 0,0,0, 255,0,0, 0,0,0, 255,0,0, 0,0,0, 255,0,0, 0,0,0, 255,0,0, 0,0,0, 255,0,0, 0,0,0, 255,0,0, 0,0,0, 255,0,0 }; if ( !(pic = (PCXPIC *) calloc( 1, sizeof(PCXPIC) )) ) return NULL; /* out of memory */ pic->hdr.x2 = hres -1; pic->hdr.y2 = vres -1; pic->hdr.maker = 10; pic->hdr.version = 5; pic->hdr.code = 1; pic->hdr.bpp = 1 + pcx_md; pic->hdr.bpl = bpl = (hres * (1+pcx_md)) / 8; VGR_HRES = pic->hdr.hres = hres; VGR_VRES = pic->hdr.vres = vres; VGR_NBPL = bpl; VGR_NCOLORS = 1 << (pic->hdr.nplanes = nplanes); movmem( (pcx_md ? cga_pal : ega_pal), pic->hdr.triple, sizeof(pic->hdr.triple) ); for ( p=0; p < nplanes; p++ ) { if ( ! (pic->rows[p] = (uchar **)calloc( 1, sizeof(char *) * vres)) ) return pcx_free_pic( pic ), (PCXPIC *)0; for ( y=0; y < vres; y++ ) if ( !(pic->rows[p][y] = (uchar *)calloc( 1, bpl )) ) return pcx_free_pic( pic ), (PCXPIC *)0; }; return pic; } int pcx_free_pic( pic ) PCXPIC *pic; { int row, plane, nrows, nplan; nrows = pic->hdr.y2 - pic->hdr.y1 +1; nplan = pic->hdr.nplanes; VGR_MODE( MODE_TEXT0 ); printf("At pcx_free_pic, probably out of memory...\n"); for ( plane = 0; plane < nplan; plane++ ) { for ( row = 0; row < nrows; row++ ) allocf( pic->rows[plane][row] ); allocf( pic->rows[plane] ); }; allocf( pic ); return NULL; } void map_not( map, len ) register unsigned int *map, len; { for ( ; len--; map++ ) *map = ~ *map; } void pcx_invert_pic( pic ) PCXPIC *pic; { int p, r, i; for ( p=0; p < pic->hdr.nplanes; p++ ) for ( r=0; r < (pic->hdr.y2 - pic->hdr.y1); r++ ) map_not( pic->rows[p][r], pic->hdr.bpl / 2 ); } allocf( p ) char *p; { if ( !p ) return OK; if ( free(p) == -1 ) CRASH( "heap munged" ); } #ifdef MAIN /* Manx 'C stack/heap size adjustment - The vgr_fill() function uses an enourmous amount of stack, and we're going to need enough heap space to allocate 4 bit maps for the EGA board. */ uint __STKLOW = 0, __STKSIZ = 4096, __HEAPSIZ = 8192; int cga_init(), ega_init(), herc_init(); int board, (*board_init)(), md; /* This structure is used here to facilitate drawing the simple X and complex box that are used to test the dot, line and fill functions. */ typedef struct { int x,y; } OBJ; static OBJ obj[] = { 100, 100, 150, 200, 200, 100, 250, 150, 175, 250, 250, 350, 200, 400, 150, 300, 100, 400, 50, 350, 125, 250, 50, 150, 100, 100 }; static OBJ obj2[] = { 0, 0,280, 0,280,140,240,140,240, 20,200, 20,200,280,240,280,240,160, 280,160,280,300, 0,300, 0,160, 40,160, 40,280, 80,280, 80, 20, 40, 20, 40,140, 0,140, 0, 0 }; static OBJ obj3[] = { 120,20, 160,20, 160,280, 120,280, 120,20 }; main( argc, argv ) char **argv; int argc; { void pcx_showpic(); FILE *fp, *fopen(); int c, h, v, p; printf("PCX test routine.\n"); if ( argc == 1 ) printf("Try \"PCX xx\" for help\n" ); board = vgr_get_board(); if ( argc >= 2 ) { if ( !strcmp(argv[1], "ega") ) board = TYPE_EGA; else if ( !strcmp(argv[1], "cga") ) board = TYPE_CGA; else if ( !strcmp(argv[1], "herc") ) board = TYPE_HERC; else if ( !strcmp(argv[1], "cga2") ) board = 9; else { printf("\ usage: PCX\n\ or PCX \n\ or PCX \n\n\ func: Excercises the board & PCX routines.\n\ may be one of:\n\ cga - 640x200x2 CGA\n\ cga2- 320x200x4 CGA\n\ herc- Hercules Hi-Res\n\ ega - 640x350x16 EGA\n\ may be any file name,\n\ although an extension of .PCX is\n\ appropriate.\n" ); exit(1); }; }; switch( board ) { case TYPE_UNKNOWN: case TYPE_MDA: CRASH("unable to detect a HERC, CGA or EGA board"); case TYPE_CGA: printf("CGA board detected\n"); board_init = cga_init; md = MODE_APA2, c = 1, h = 640, v=200, p=1; break; case 9: printf("CGA/APA3 Selected\n"); board_init = cga_init; md = MODE_APA3, c = 2, h = 320, v=200, p=1; break; case TYPE_EGA: printf("EGA board detected\n"); board_init = ega_init; md = MODE_APA0, c = 9, h = 640, v=350, p=4; break; case TYPE_HERC: printf("HERC board detected\n"); board_init = herc_init; md = MODE_APA1, c = 1, h = 720, v=348, p=1; break; default: CRASH("bug: invalid board type number"); }; printf("Hit return to continue:"); getchar(); /* pcx_init_pic needs to know what mode it's in */ pcx_init(); pcx_mode( md ); if ( !(pcx_cpic = pcx_init_pic( h, v, p )) ) CRASH("out of memory"); pcx_init(); if ( VGR_MODE( md ) ) CRASH( "error in mode selection" ); printf("HRES=%d, VRES=%d, NCOLORS=%d, NPLANES=%d, pcx_md=%d\n", VGR_HRES, VGR_VRES, VGR_NCOLORS, p, pcx_md ); draw_it( (OBJ *)&obj, NELEMS(obj) , 3, 3, 0, 0, c ); printf("."); draw_it( (OBJ *)&obj2, NELEMS(obj2), 3, 3, 150, 0, c ); printf("."); draw_it( (OBJ *)&obj3, NELEMS(obj3), 3, 3, 150, 0, c ); printf("."); vgr_fill( 33, 40, c ); printf("."); vgr_fill( 179, 19, c ); printf("\nhit return to continue, then hit return again:"); getchar(); if ( (*board_init)() ) CRASH( "board init failed" ); if ( VGR_MODE( md ) ) CRASH( "error in mode selection" ); pcx_showpic( pcx_cpic, 0, 0, 0 ); getchar(); VGR_MODE( MODE_TEXT0 ); if ( argc == 3 ) { if ( !(fp = fopen( argv[2], "w" )) ) CRASH( "error opening picture file" ); if ( pcx_write_pic( pcx_cpic, fp ) ) CRASH( "error writing picture file" ); fclose(fp); }; exit(0); } draw_it( obj, n, divx, divy, ox, oy, c ) OBJ *obj; int n, divx, divy; { int x; vgr_point( obj[0].x / divx + ox, obj[0].y / divy + oy, -1 ); for ( x=1; x < n; x++ ) vgr_point( obj[x].x / divx + ox, obj[x].y / divy + oy, c ); } #endif