//------------------------------------------------------------------- // pcxphoto.cpp // // This Linux program must be run from a 'text mode' console. // It will display the truecolor image stored in a .pcx file. // // compile using: $ g++ pcxphoto.cpp int86.cpp -o pcxphoto // // programmer: ALLAN CRUSE // written on: 01 SEP 2003 // revised on: 25 AUG 2005 -- replace 'mode3' with 'int86()' //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for read() #include // for exit() #include // for mman() #include "int86.h" // for init8086(), int86() #include "pcx.h" // for PCX_FILE_HEADER #define VRAM_BASE_ADDRESS 0xA0000000 typedef unsigned long PEL; PEL *fb = (PEL*)VRAM_BASE_ADDRESS; int vesa_mode = 0x4121, hres = 640, vres = 480; char devname[] = "/dev/vram"; char pcxname[] = "issxmas.pcx"; struct vm86plus_struct vm; void draw_rectangle( int x, int y, int h, int v, PEL color ); void fill_rectangle( int x, int y, int h, int v, PEL color ); int main( int argc, char **argv ) { PCX_FILE_HEADER pcxHeader; // read the .pcx image-file's header int fd = open( pcxname, O_RDONLY ); if ( fd < 0 ) { perror( pcxname ); exit(1); } if ( read( fd, &pcxHeader, sizeof( pcxHeader ) ) < 0 ) { perror( "read" ); exit(1); } // verify the file-format parameters if (( pcxHeader.manuf != 10 )||( pcxHeader.rle != 1 )) { fprintf( stderr, "unsupported file-format\n" ); exit(1); } // allocate storage for the uncompressed image int wide = pcxHeader.x2 - pcxHeader.x1; int high = pcxHeader.y2 - pcxHeader.y1; int bytes_per_scanline = pcxHeader.bplin; int npixels = wide * high; int *image = (int*)calloc( npixels, sizeof( PEL ) ); if ( !image ) { perror( "calloc" ); exit(1); } // read and uncompress the .pcx file's image data int i = 0; while ( i < npixels ) { int datum = 0; read( fd, &datum, 1 ); if ( datum < 0xC0 ) image[ i++ ] = datum; else { int reps = datum & 0x3F; read( fd, &datum, 1 ); do { image[ i++ ] = datum; } while ( --reps > 0 ); } } // read the image-file's colors unsigned char rgb[ 768 ]; lseek( fd, -768, SEEK_END ); read( fd, rgb, 768 ); // build the color lookup-table PEL colortable[ 256 ]; for (i = 0; i < 256; i++) { PEL color = 0; color |= ( rgb[ 3*i + 0 ] << 16 ); // red intensity color |= ( rgb[ 3*i + 1 ] << 8 ); // green intensity color |= ( rgb[ 3*i + 2 ] << 0 ); // blue intensity colortable[ i ] = color; } // report some image-file statistics printf( "\ngraphic image filename: \'%s\' ", pcxname ); printf( "\nimage size (in pixels): wide=%d high=%d ", wide, high ); printf( "\n\n" ); getchar(); // map the vram device's display-memory into user-space int dd = open( devname, O_RDWR ); if ( dd < 0 ) { perror( devname ); exit(1); } int size = (2 << 20); // 2 megabytes int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)VRAM_BASE_ADDRESS; if ( mmap( mm, size, prot, flag, dd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // enter graphics mode init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = vesa_mode; int86( 0x10, vm ); if ( vm.regs.eax != 0x004F ) { fprintf( stderr, "cannot set mode %04X \n", vesa_mode ); exit(1); } // draw red and green screen borders PEL red = 0xFF0000, green = 0x00FF00; int x = 0, y = 0, h = hres, v = vres; draw_rectangle( x, y, h, v, red ); // outer border x += 8; y += 8; h -= 16; v -= 16; draw_rectangle( x, y, h, v, green ); // inner border getchar(); // draw color lookup-table grid int xindent = ( hres - 160 )/2, yindent = ( vres - 160 )/2; for (i = 0; i < 256; i++) { x = xindent + (i % 16)*10; y = yindent + (i / 16)*10; fill_rectangle( x, y, 8, 8, colortable[ i ] ); } getchar(); // write the uncompressed image to display memory xindent = ( hres - wide )/2; yindent = ( vres - high )/2; for (i = 0; i < npixels; i++) { x = xindent + (i % bytes_per_scanline); y = yindent + (i / bytes_per_scanline); fb[ y*hres + x ] = colortable[ image[i] ]; } getchar(); // restore the video display system to standard text mode vm.regs.eax = 0x0003; int86( 0x10, vm ); printf( "\n" ); } void draw_rectangle( int x, int y, int h, int v, PEL color ) { int minx = x, maxx = x+h-1, miny = y, maxy = y+v-1; do { fb[ y*hres + x ] = color; ++x; } while ( x < maxx ); do { fb[ y*hres + x ] = color; ++y; } while ( y < maxy ); do { fb[ y*hres + x ] = color; --x; } while ( x > minx ); do { fb[ y*hres + x ] = color; --y; } while ( y > miny ); } void fill_rectangle( int x, int y, int h, int v, PEL color ) { int minx = x, maxx = x+h-1, miny = y, maxy = y+v-1; for (y = miny; y <= maxy; y++) for (x = minx; x <= maxx; x++) fb[ y*hres + x ] = color; }