ECE291 Computer Engineering II Peter Johnson
(originally Jason Gallicchio,
J. W. Lockwood)

Lecture 22

Today's Topics

  1. Storing Images (Full Color vs Palettes)
  2. Video Hardware
  3. DO Try this Stuff at Home -- Mode 13h
  4. High Resolution, High Color
  5. String Instructions
  6. Graphics File Formats
  7. BMP Format is Backwards
  8. PNG File Format
  9. PCX Format and RLE Compression

Storing Images

Color Theory

  • TV's, Computer Monitors, Projectors...  It's all (Red, Green, Blue)
  • Why (Red, Green, Blue)?  You can get all the colors this way.
  • Red + Green = Yellow
  • Green + Blue = Cyan
  • Blue + Red = Purple
  • That's how I made this web page.  Look at the font tag.   Colors are RRGGBB in hex.
  • <font color="FF00FF">Purple</font>
  • Why?  How could mixing Low Frequency with High Frequency make Really High Frequency?
  • It can't.  Remember your ECE 210.  It's purely biological.
  • We just happen to have Red Green and Blue sensors in our eyes, and since that's all we can SEE, people who invented Color Photography and Color TV took advantage of that fact.
  • If aliens (or animals) with different sensors came down, they'd see the same three frequencies coming from the monitor, but they wouldn't be able to see a picture of a rainbow even if they could actually see a real one.

Full Color Images

Palette Images

Text Mode Video


Video Hardware

video-card.gif (4543 bytes)


Paletted Graphics -- Mode 13h

Mode 13h is a 320x200x256-color display mode that was very popular for DOS programming due to its relatively high number of colors (256 compared to 16 for other VGA modes) and simple addressing. Advantages of Mode 13h:

How to get into Mode 13h  (To get back to text mode, change 13h to 3h)

mov ah, 0     ; int 10h's subfuntion to set mode
mov al, 13h   ; Mode 13h = 320x200x256 colors
int 10h       ; Call the VBIOS interrupt

How to draw a pixel

VidGrSeg  equ    0A000h
Location  dw     (200/2)*320+(320/2) ; Center
Color     db     98   ; Some random palette index

mov ax, VidGrSeg    ; VidGrSEG = 0A000h
mov es, ax          ; Use Extra Segment
mov bx, Location    ; Location = R*320+C
mov al, Color       ; Palette Entry Number
mov es:[bx], al     ; Write it to the Screen

How to Change the Palette

; Change a palette entry to light purple

Red    db   39
Green  db   0
Blue   db   63

mov bx, Color  ; We'll change the pixel we just wrote
mov ch, Green
mov cl, Blue
mov dh, Red
mov ax, 1010h   ; int 10's subfunction to set palette
int 10h

Full Source Code to do all this Stuff.


High Resolution, High Color

Mode 13h may look a little outdated from a modern programming perspective. It's very low resolution (320x200), and even 256 colors doesn't seem like a lot now that we're all running Windows at a resolution of 1024x768 (or higher), with 16-bit or 24-bit color. The basic layout of Mode 13h is good to know because most modern video memories try to follow its linear layout.

Somewhat suprisingly, Mode 13h managed to stay popular even as graphics cards far exceeded its limited capabilities, simply because there was little standardization between video card manufacturers for the higher resolution and color modes usually called SVGA, Super VGA (Mode 13h had been standardized by IBM back in the PC/AT days).

A standard known as the VESA VBE tried to standardize SVGA in the mid '90s, but by then it was too little, too late: the growing popularity of Windows on the desktop led to video card manufacturers writing drivers for Windows rather than supporting the VESA standard. DirectX was essentially another nail in the coffin: even though many video cards now claim VESA support, usually the support is lackluster, only supporting a few lower-resolution modes.

The other major issue with programming for high-resolution graphics modes is the large amount of memory required (see above section on full color images for some numbers). This tends to make high-res graphics almost unusable under real mode (you can do banked modes, but that's just a pain). In protected mode things are a lot easier: you can have a linear memory region that can hold the entire graphics screen.

In this class, we will be programming high-resolution, high-color graphics, but not through the standard VESA interface because of its complexity and massive variability between machines (the VESA VBE was written to make it easy for video card manufacturers to add at least limited support for it, not to make it easy for programmers to code). Instead, we will be using a custom ECE 291 driver package for Windows 2000 and NT which provides a clean interface for you to access.

Features of the 291 high-resolution graphics driver:

How to get into 32-bit color mode using protected mode library

invoke _SetGraphics, dword 640, dword 480

How to draw a pixel (NASM, Protected Mode)


%include "lib291.inc"
 ...
SECTION .data
 ...
X        dd  640/2                  ; Center
Y        dd  480/2
MemColor db  080h, 0FFh, 000h, 000h ; Bytes reversed in memory: BGRxBGRx etc.
                                    ; So this is light green
 ...
SECTION .text
 ...
mov eax, 00FF8000h                  ; Not reversed in register: xRGB,
                                    ; So this is Orange (R=255, G=128, B=0)

mov es, [_VideoBlock]               ; _VideoBlock is declared in the library
mov ecx, [Y]
lea ecx, [ecx+ecx*4]                ; Offset = Y * 5 using 386 instructions
shl ecx, 7                          ; Offset = Y * 128 * 5 = Y * 640
add ecx, [X]                        ; Offset = Y * 640 + X (note no multiply!)
shl ecx, 2                          ; 4 bytes per pixel

mov [es:ecx], eax                   ; Write orange to the Screen
add ecx, 4                          ; Move one pixel to the right
mov edx, [MemColor]
mov [es:ecx], edx                   ; Write light green pixel to screen

add ecx, (640-1)*4                  ; Go to pixel below orange pixel
mov [es:ecx], edx                   ; Write another light green pixel

call _RefreshVideoBuffer            ; Update what's on screen (library call)

Full Source Code to demo all this stuff.

To compile this source, you'll need the 291 protected mode library, available at V:\pmodelib.

To run it, you'll first need to go to V:\utils and run ex291 or ex291w (ex291 is fullscreen, ex291w is windowed) to load the ECE 291 graphics driver. If you run ex291w, you must first set the display depth to 24 bit in the Windows display control panel.


String Instructions for Fast Data Movement

Set Direction First:

MOVS - Move source to destination

MOVSB (byte) MOVSW (word) MOVSD (dword)
mov byte [es:di],
    byte [ds:si]
add si, 1  ; If CLD
add di, 1
mov word [es:di],
    word [ds:si]
add si, 2  ; If CLD
add di, 2
mov dword [es:edi],
    dword [ds:esi]
add esi, 4  ; If CLD
add edi, 4

CMPS - Compare source to destination and set ZF if ES:[DI] = DS:[SI]

CMPSB (byte) CMPSW (word) CMPSD (dword)
cmp byte [es:di],
    byte [ds:si]
add si, 1  ; If CLD
add di, 1
cmp word [es:di],
    word [ds:si]
add si, 2  ; If CLD
add di, 2
cmp dword [es:edi],
    dword [ds:esi]
add esi, 4  ; If CLD
add edi, 4

STOS - Store AL/AX/EAX into destination

STOSB (byte) STOSW (word) STOSD (dword)
mov byte [es:di], al
add di, 1  ; If CLD
mov word [es:di], ax
add di, 2  ; If CLD
mov dword [es:edi], eax
add edi, 4  ; If CLD

LODS - Load destination into AL/AX/EAX.

LODSB (byte) LODSW (word) LODSD (dword)
mov al, byte [ds:si]
add si, 1  ; If CLD
mov ax, word [ds:si]
add si, 2  ; If CLD
mov eax, dword [ds:esi]
add esi, 4  ; If CLD

SCAS - Compare destination to AL/AX/EAX and set ZF if ES:[DI] = Al/AX/EAX

SCASB (byte) SCASW (word) SCASD (dword)
cmp byte [es:di], al
add di, 1  ; If CLD
cmp word [es:di], ax
add di, 2  ; If CLD
cmp dword [es:edi], eax
add edi, 4  ; If CLD

REP - What makes all this useful.

Example:  Blitting a Double Buffer

cld  ; Make sure we go up

; Set up Source
mov  si,  offset DoubleBuffer  ;  Offset with respect to ds

; Set up Destination
mov  ax,  VidGrSeg
mov  es,  ax            ; Set destination segment as es
mov  di,  0             ; Start of screen

; Set up counter
mov  cx,  (320*200)/4   ; We're moving 4 bytes at at time

rep  movsd              ; This takes a while.

Graphics File Formats

The File Itself


BMP is Backwards

  For an uncompressed, 16-color BMP, this is the header:

BMPHEADERTYPE STRUC
; --- BitMapFileHeader --- ; 14 bytes
   BFType DB 'BM' ; File Type
   BFSize DD ? ; File Size (in Bytes)
   BFReserved1 DW 0 ; Reserved
   BFReserved2 DW 0 ; "
   BFOffBits DD ? ; Offset to start of image data
; --- BitMapInfoHeader --- ; 40 bytes
   BISize DD ? ; Size of BitMapInfoHeader (28h = 40d)
   BIWidth DD ? ; # Pixel Rows
   BIHeight DD ? ; # Pixel Columns
   BIPlanes DW 1 ;
   BIBitCount DW ? ; Log2(palette size) = 4 for 16-color image
   BICompression DD 0 ; RGB = 0 = Uncompressed
   BISizeImage DD ? ; Size of Image (Bytes)
   BIXPelsPerMeter DD ? ;
   BIYPelsPerMeter DD ? ;
   BIColorsUsed DD 0 ; 0=All
   BIColorsImportant DD 0 ;
; --- Color Table --- ; 64 Bytes
   RGBQuad DB 16 dup ( 4 dup(?) ) ; Blue, Green, Red, Unused
BMPHEADERTYPE ENDS

PNG File Format

PNG was introduced as a replacement for GIF in 1995. GIF's LZW compression is patented, so any program which saves GIF's with that compression requires a license from Unisys, who holds the patent on LZW compression. The PNG development group is web-based, so you can look at PNG's history and a A list of PNG features on the web.

While PNG is a very cool graphics format, it is difficult to write and read directly. Luckily for everyone, the PNG group created libpng to make it (relatively) easy to read from and write to PNG files.

The primary reason you'll want to use PNG is for its high compression (it uses the unpatented ZIP deflate algorithm) and for its large number of color formats, including some with a 8-bit alpha channel (far better than the all or nothing transparency of GIF).


PCX and RLE Endoding

A PCX Header Structure:

PCX_HEADER STRUC
  MANUFACTURER   DB  10            ; A ZSoft PCX File
  VERSION        DB  ?
  ENCODING       DB  1
  BITS_PER_PIXEL DB  ?             ; 1,2,4,8,24 (8 for ECE291 images)
  XMIN           DW  ?
  YMIN           DW  ?
  XMAX           DW  ?             ; Window
  YMAX           DW  ?
  HORZ_DPI       DW  ?             ; Horizontal/Vertical Dots per inch 
  VERT_DPI       DW  ?
  PALETTE        DB  48 DUP (?)    ; For Palettes with <= 16 colors
  RESERVED       DB  ?
  COLOR_PLANES   DB  ?
  BYTES_PER_LINE DW  ?
  PALETTE_TYPE   DW  ?
  HSCR_SIZE      DW  ?             ; only supported by
  VSCR_SIZE      DW  ?             ; PBrush IV or higher
  FILLER         DB  54 DUP (?)
PCX_HEADER ENDS

PCX_DATA STRUC
  IMAGE_DATA     DB  FileSize DB ? ; RLE-Encoded Data (line-by-line)
PCX_DATA ENDS

PCX_TRAILER STRUC
  PALETTE_MARK  DB 12              ; Indicates Trailer Palette
  PALETTE_256C  DB 256 DUP('RGB')  ; 768 Bytes of Palette Data
PCX_TRAILER ENDS

RLE Compression -- Why and How does it work?

PCX RLE Decompression Algorithm

  • Read a Byte
  • If it's top two bits are set, this means it's a length byte  (so what's the max run length?)
    • The next byte will be the color byte, so copy it "length" number of times onto the screen
  • Else, it was a single color byte
    • Copy it onto the screen
  • Loop until finished

RLE Caveat

Samples

References