//------------------------------------------------------------------- // pcx8bpp.cpp // // This program displays the photograph stored in a .pcx file // using the VGA hardware's color-lookup table in 8-bpp mode. // // compile using: $ g++ pcx8bpp.cpp int86.cpp -o pcx8bpp // // programmer: ALLAN CRUSE // written on: 27 AUG 2005 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read() #include // for mmap() #include // for outb() #include "int86.h" // for init8086(), int86() #include "pcx.h" // for PCX_FILE_HEADER #define VRAM_BASE 0xA0000000 #define DAC_PORT 0x03C8 typedef unsigned char PEL; PEL *vram = (PEL*)VRAM_BASE; int vesa_mode = 0x4101, hres = 640, vres = 480; char devname[] = "/dev/vram"; char pcxname[] = "issxmas.pcx"; struct vm86plus_struct vm; int main( int argc, char **argv ) { // open the vram device file int dd = open( devname, O_RDWR ); if ( dd < 0 ) { perror( devname ); exit(1); } // map the display memory into user space int size = hres * vres; int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)VRAM_BASE; if ( mmap( mm, size, prot, flag, dd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // open the image file int fd = open( pcxname, O_RDONLY ); if ( fd < 0 ) { perror( pcxname ); exit(1); } // memory-map the .pcx file into user-space size = lseek( fd, 0, SEEK_END ); prot = PROT_READ; flag = MAP_PRIVATE; mm = mmap( NULL, size, prot, flag, fd, 0 ); if ( mm == MAP_FAILED ) { perror( "mmap" ); exit(1); } // setup structure-pointers and display the image's parameters PCX_FILE_HEADER *pcx = (PCX_FILE_HEADER*)mm; unsigned char *image = (unsigned char*)((int)mm + 128 ); unsigned char *table = (unsigned char*)((int)mm + size - 3*256 ); int wide = pcx->x2 - pcx->x1; int high = pcx->y2 - pcx->y1; int npixels = wide * high; int bytes_per_scanline = pcx->bplin; printf( "\nimage file: \'%s\' (%d bytes) \n", pcxname, size ); printf( "screen resolution: %d-by-%d \n", wide, high ); printf( "color depth: %d-bpp \n", pcx->bitpx ); getchar(); // set the graphics display mode init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = vesa_mode; int86( 0x10, vm ); if ( vm.regs.eax != 0x004F ) { fprintf( stderr, "cannot set vesa mode %04X\n", vesa_mode ); exit(1); } // draw a screen border PEL color = 7; int x = 0, y = 0; do { vram[ y*hres + x ] = color; ++x; } while ( x < hres-1 ); do { vram[ y*hres + x ] = color; ++y; } while ( y < vres-1 ); do { vram[ y*hres + x ] = color; --x; } while ( x > 0 ); do { vram[ y*hres + x ] = color; --y; } while ( y > 0 ); getchar(); // draw the (uncompressed) image to display memory int xstart = (hres - wide)/2; int ystart = (vres - high)/2; int src = 0, dst = 0; // source and dest'n counters while ( dst < npixels ) { int reps = 1; // repetitions count (default=1) PEL datum = image[ src++ ]; if ( ( datum & 0xC0 ) == 0xC0 ) { reps = (datum & 0x3F); datum = image[ src++ ]; } while ( reps-- > 0 ) { y = ystart + (dst / bytes_per_scanline); x = xstart + (dst % bytes_per_scanline); vram[ y*hres + x ] = datum; ++dst; } } getchar(); // now reprogram the VGA Color-Lookup Registers for (int reg = 0; reg < 256; reg++) { outb( reg, DAC_PORT ); outb( table[ 3*reg + 0 ]>>2, DAC_PORT+1 ); outb( table[ 3*reg + 1 ]>>2, DAC_PORT+1 ); outb( table[ 3*reg + 2 ]>>2, DAC_PORT+1 ); } getchar(); // ok, now reprogram the color-registers for GrayScale for (int reg = 0; reg < 256; reg++) { int r = 0, g = 0, b = 0; outb( reg, DAC_PORT-1 ); // select register to read r = inb( DAC_PORT+1 ); // read 'red' component g = inb( DAC_PORT+1 ); // read 'green' component b = inb( DAC_PORT+1 ); // read 'blue' component int avg = (30*r + 59*g + 11*b)/100; outb( reg, DAC_PORT ); // select register to write outb( avg, DAC_PORT+1 ); // write 'red' component outb( avg, DAC_PORT+1 ); // write 'green' component outb( avg, DAC_PORT+1 ); // write 'blue' component } getchar(); // reset textmode display vm.regs.eax = 0x4F02; vm.regs.ebx = 0x0003; int86( 0x10, vm ); printf( "\n\n" ); }