| ECE291 | Computer Engineering II | Peter Johnson (originally Jason Gallicchio, J. W. Lockwood) |
Lecture 22
Color Theory
|
Full Color Images
Palette Images
Text Mode Video
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.
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.
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. |
The File Itself
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 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).
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
|
RLE Caveat
Samples
References