Giáo trình Đồ họa trong Pascal - Chương 1: Màn hình của máy tính - Bài 2: Truy cập vào bộ nhớ màn hình
Về nguyên tắc có 2 cách để truy cập bộ nhớ màn hình và các thanh ghi
+ Cách 1: Sử dụng các dịch vụ ngắt của ROM BIOS, ROM BIOS cung cấp tương đối đầy đủ các chương trình con ứng với các ngắt để phục vụ cho công việc này
+ Cách 2: Truy cập trực tiếp đưa vào các địa chỉ của các cổng (port) thông qua các ngôn ngữ lập trình
Cách 1 đơn giản tuy nhiên có nhược điểm tốc độ truy nhập chậm
I. Sử dụng các dịch vụ ngắt Int 10H của ROM BIOS
Dưới đây là một vài ngắt của ROM BIOS
1. Đưa một pixel vào bộ nhớ màn hình
input AH=0Ch
AL=màu
BH=trang
CX=x (cột)
DX=y (dòng)
Procedure writepixel(col,row,color: integer);
Var
v : Registers;
Begin
v.ah:=$0C;
v.al := color;
v.bh:=0;
v.cx:=col;
v.dx:=row;
intr($10,v);
End;
2. Đọc dữ liệu của một pixel
input AH=ODh
BH=trang
CX=x (cột)
DX=y (dòng)
output: AL=Color (giá trị màu của pixel)
Function readpixel(col,row: integer): integer;
Var
v : Registers;
Begin
v.ah:=$0D;
v.bh:=0;
v.cx:=col;
v.dx:=row;
intr($10,v);
readpixel:=v.al;
end;
3. Đọc dữ liệu từ thanh ghi màu (color Register)
Input: AH=10h
AL=15h
BX=n (số hiệu thanh ghi màu)
Output: CH=độ kích hoạt màu Green
CL=độ kích hoạt màu Blue
DH=độ kích hoạt màu Red
Type
RGB_COLOR_TYP = Record
red : Word;
green : Word;
blue : Word;
End;
Procedure read_color_reg(index: integer;Var color: RGB_COLOR_TYP);
Var
R : registers;
Begin
R.ax:=$1015;
R.bx:=index;
intr($10,R);
color.red:=R.dh;
color.green:=R.ch;
color.blue:=R.cl;
End;
và 4 bit màu đó lại nằm trong 4 byte ở cùng vị trí giống như ở bảng trên. Ta hãy xem lại nhóm 2 (Sequencer Register), trong nhóm này thanh ghi số 2 (Map Mask) sẽ xác định bit plane nào được truy cập: Tên thanh ghi Chỉ số thanh ghi Địa chỉ ghi vào Địa chỉ đọc ra address 3C4 3C4 Map mask 2 3C5 3C5 Mỗi lần đưa số liệu vào bộ nhớ màn hình, 4 byte được đưa vào 4 bit plane. Thanh ghi Map Mask có nhiệm vụ xem bit plane nào được sửa đổi. Dạng của thanh ghi này như sau: b3 b2 b1 b0 0001, 0010, 0100, 1000 để truy nhập vào một bit plane ta cần hai lệnh Lệnh 1 : xác định thanh ghi cần truy nhập là thanh ghi mapmask Lệnh 2 : đưa số liệu bit plane cần truy cập vào thanh ghi mapmask Hai lệnh có dạng: port[$3C4]:=2; (Vào thanh ghi cần truy cập) port[$3C5]:= n; (đưa số liệu bitplan cần truy cập vào thanh ghi Mapmask) (n=1,2,4,8) Và ta cần 4 lần như vậy để truy cập vào 4 bit plane Thủ tục ghi 8 điểm ra màn hình bằng 4 byte : Procedure write_8_pixel(x,y: integer; Var b: four_byte); Var j,address: Integer; Begin port[$3c4]:=2; address:=y*80+(x shr 3); j:=1; For i:=0 To 3 Do Begin port[$3c5]:=j; Mem[buffer:address]:=b[i]; j:=j*2; End; End; Để đọc trên màn hình trong chế độ 4 bit plane chúng ta phải đọc đồng thời 8 điểm, mỗi điểm gồm có 4 bit màu và 4 bit màu đó lại nằm trong 4 byte ở cùng vị trí. Ta chú ý đến nhóm thanh ghi thứ 4 (Graphics Control Register). Trong nhóm có thanh ghi mang chỉ số 4 (Read Map), thanh ghi này xác định bit plane nào sẽ được phép đưa số liệu ra : Tên gọi thanh ghi Chỉ số Địa chỉ ghi Địa chỉ đọc Graphics address 3CE 3CE Read Map 4 3cf 3cf Để thực hiện phép đọc một bit plane nào đó chúng ta cần có hai lệnh: Lệnh 1. Xác định số hiệu của thanh ghi trong nhóm cần truy nhập Lệnh 2: Xác định số hiệu bitplane Lệnh 1: Port($3ce):=4; Lệnh 2: Port($3cf):=bitplane; Và ta cần 4 lần như vậy để truy cập vào 4 bit plane Type four_byte = array[0..3] of Byte; Thủ tục đọc 8 điểm trên màn hình vào 4 byte : Procedure read_8_pixel(x,y: integer; Var b: four_byte); Var address,color: integer; Begin address:=y*80+(x shr 3); port[$3ce]:=4; for i:=0 To 3 Do Begin port[$3cf]:=i; b[i]:=Mem[buffer:address]; End; End; Thủ tục vẽ một điểm : để vẽ một điểm trên màn hình ta đọc 4 byte liên quan đến điểm đó (4 byte ứng với 8 điểm có chứa điểm cần vẽ), mà vị trí của điểm cần vẽ trong 8 điểm đánh số từ 0 đến 7 là p=7-(x mod 8), sau đó ta thay bit thứ p của mỗi byte trong 4 byte đó bằng bit màu cần vẽ (bằng cách đổi màu cần vẽ điểm ra cơ số 2 ví dụ n=5 thì n=0101) Procedure putdot(x,y,n: integer); Var p,m: byte; ma: four_byte; Begin p:=7-(x mod 8); m:=1; For i:=1 To p Do m:=m*2; For i:=0 To 3 Do Begin ma[i]:=(n shr i) mod 2; ma[i]:=ma[i]*m; End; read_8_pixel(x,y,b); For i:=0 To 3 Do Begin If ma[i]=0 Then b[i]:=b[i] And ($FF-m) Else b[i]:=b[i] Or ma[i]; End; write_8_pixel(x,y,b); End; Ví dụ 4: Ghi một điểm ảnh vào bộ nhớ màn hình ở chế độ 4 bit plane thông qua cổng. Program Four_Bit_Planes; Uses Crt,dos; Const buffer: Word=$A000; gd: integer=0; Type four_byte = array[0..3] of Byte; Var gm,x,y,i: integer; b: four_byte; (**********************) Procedure set_mode(mode: integer); Var R : registers; Begin R.ax:=$4f02; R.bx:=mode; intr($10,R); End; (**********************) Procedure write_8_pixel(x,y: integer; Var b: four_byte); Var j,address: Integer; Begin port[$3c4]:=2; address:=y*80+(x shr 3); j:=1; For i:=0 To 3 Do Begin port[$3c5]:=j; Mem[buffer:address]:=b[i]; j:=j*2; End; End; (**********************) Procedure read_8_pixel(x,y: integer; Var b: four_byte); Var address,color: integer; Begin address:=y*80+(x shr 3); port[$3ce]:=4; for i:=0 To 3 Do Begin port[$3cf]:=i; b[i]:=Mem[buffer:address]; End; End; (**********************) Procedure putdot(x,y,n: integer); Var p,m: byte; ma: four_byte; Begin p:=7-(x mod 8); m:=1; For i:=1 To p Do m:=m*2; For i:=0 To 3 Do Begin ma[i]:=(n shr i) mod 2; ma[i]:=ma[i]*m; End; read_8_pixel(x,y,b); For i:=0 To 3 Do Begin If ma[i]=0 Then b[i]:=b[i] And ($FF-m) Else b[i]:=b[i] Or ma[i]; End; write_8_pixel(x,y,b); End; (**********************) Begin Set_mode($12); y:=150; for x:=0 To 639 Do putdot(x,y,Magenta); Readkey; y:=300; for x:=0 To 639 Do putdot(x,y,Yellow); Readkey; Set_mode(3); End. Ví dụ 5: Đọc dữ liệu từ chế độ 4 bit plane thông qua các cổng của các thanh ghi Đoạn chương trình sau mô tả cách đọc một điểm ảnh từ bộ nhớ màn hình Program Read_Pixel_Color; Uses Crt,dos,graph; Const buffer: Word=$A000; gd: integer=0; Var gm,x,y: integer; Function getdot(x,y: integer): integer; Var i,address,b,color: integer; c: array[0..3] of integer; Begin address:=y*80+(x shr 3); port[$3ce]:=4; b:=x mod 8; for i:=0 To 3 Do Begin port[$3cf]:=i; c[i]:=Mem[buffer:address]; c[i]:=c[i] shl b; c[i]:=c[i] shr 7; End; color:=c[0]+2*c[1]+4*c[2]+8*c[3]; getdot:=color; End; Begin initgraph(gd,gm,'c:\tp\bgi'); directvideo:=false; x:=320;y:=240; putpixel(x,y,WHITE); Writeln('Mau cua diem la : ',getdot(x,y)); readkey; closegraph; End. 3. Chế độ 640x480 256 màu (mode $101) Ta xét trường hợp đọc/ghi vào bộ nhớ màn hình ở chế độ 256 màu theo chuẩn VESA (chú ý trong TP ứng với mode $101 độ phân giải 640x480, 256 màu) ở chế độ này bộ nhớ màn hình được tổ chức thành 5 mảng một chiều, mỗi mảng gồm 65536 phần tử (mỗi phần tử là 1 byte, mỗi byte ứng với 1 pixel) và do đó ta cần có 5 mảng đánh số từ 0 đến 4 để có thể chứa được 640x480 byte. Mỗi một mảng như vậy gọi là một Bank (dải), như vậy một bank 64K đúng bằng 64K mà bộ nhớ của máy chủ dành cho màn hình, mà có 5 bank như vậy (do đó bộ nhớ màn hình phải có ít nhất là 64K x 5 = 320K thì mới có thể đặt được chế độ này) và bộ nhớ của máy chủ chỉ có thể ánh xạ vào một bank của bộ nhớ màn hình và để cho bank (từ 0-4) nào được ánh xạ ta dùng thủ tục sau : Procedure setbank(banknum: Integer); Var R : Registers; Begin R.ax:=$4f05; R.bx:=0; R.dx:=banknum; Intr($10,R); End; Một điểm có toạ độ (x,y) trên màn hình sẽ là điểm thứ linear_address:=y*640+x; Mà mỗi một bank có 65536 điểm nên điểm đó sẽ nầm ở bank thứ bank_num:=linear_address Div 65536; và địa chỉ của điểm đó ở bank này là pixel_offset:=linear_address Mod 65536; Ví dụ 6: Đoạn chương trình sau mô tả thủ tục đọc/ghi điểm ảnh ở chế độ 256 màu Program VGA_256_Color; Uses Crt,Dos; Const buffer: Word=$A000; Var v : Registers; x,y,mode: Integer; Procedure set_mode(mode: Integer); Begin v.ax:=$4f02; v.bx:=mode; Intr($10,v); End; Procedure setbank(banknum: Integer); Begin v.ax:=$4f05; v.bx:=0; v.dx:=banknum; Intr($10,v); End; Procedure putdot(x,y: LongInt; color: Integer); Var linearaddress: LongInt; banknum: Integer; pixeloffset: Word; Begin linearaddress:=y*640+x; banknum:=linearaddress Div 65536; pixeloffset:=linearaddress Mod 65536; setbank(banknum); Mem[buffer:pixeloffset]:=color; End; Function getdot(x, y: LongInt): Integer; Var linearaddress: LongInt; banknum,color: Integer; pixeloffset: Word; Begin linearaddress:=y*640+x; banknum:=linearaddress Div 65536; pixeloffset:=linearaddress Mod 65536; setbank(banknum); getdot:=Mem[buffer:pixeloffset]; End; Begin clrscr; mode:=$101; (* 640x480, 256 mau *) set_mode(mode); directvideo:=False; x:=320; y:=240; putdot(x,y,WHITE); Writeln('Mau cua diem la : ',getdot(x,y)); Readkey; mode:=3; (*80x25x16*) set_mode(mode); End. Ví dụ 7: đọc nội dung thanh ghi màu thông qua cổng Program Read_Write_Color_Registers; Uses crt,graph,dos; Const COLOR_MASK=$3C6; COLOR_REG_RD=$3C7; COLOR_REG_WR=$3C8; COLOR_DATA= $3C9; Type RGB_COLOR_TYP = Record red : Word; green : Word; blue : Word; End; Procedure set_ mode(mode: integer); Var R : registers; Begin R.ax:=$4f02; R.bx:=mode; intr($10,R); End; Procedure write_color_reg(index: Integer;color: RGB_COLOR_TYP); Begin port[COLOR_REG_WR]:=index; port[COLOR_DATA]:=color.red; port[COLOR_DATA]:=color.green; port[COLOR_DATA]:=color.blue; End; Procedure read_color_reg(index: integer;Var color: RGB_COLOR_TYP); Begin port[COLOR_REG_RD]:=index; color.red:=port[COLOR_DATA]; color.green:=port[COLOR_DATA]; color.blue:=port[COLOR_DATA]; End; Var VIDEO_BUFFER : Word; gd,gm,x,y,index: integer; color: RGB_COLOR_TYP; Begin clrscr; VIDEO_BUFFER:=$A000; gm:=$13; set_ mode(gm); directvideo:=false; index:=WHITE; read_color_reg(index,color); Writeln('3 mau cua thanh ghi mau WHITE la: '); Writeln('Red: ',color.red,'; Green: ',color.green,'; Blue: ',color.blue); Readkey; index:=BLUE; color.red:=63; color.green:=0; color.blue:=63; write_color_reg(index,color); (* Ve duong thang ngang *) y:=100; for x:=0 To 319 Do Mem[VIDEO_BUFFER:y*320+x]:=index; Readkey; gm:=3; (* Text Mode *) set_graph_mode(gm); End. Ví dụ 8: làm màn hình sáng tối dần dần Program Display; Uses crt,dos; Const COLOR_MASK=$3C6; COLOR_REG_RD=$3C7; COLOR_REG_WR=$3C8; COLOR_DATA= $3C9; b: Integer = 1; type RGB_COLOR_TYP = Record red : Word; green : Word; blue : Word; End; Procedure set_mode(mode: integer); Var R : registers; Begin R.ax:=$4f02; R.bx:=mode; intr($10,R); End; Procedure write_color_reg(index: Integer;color: RGB_COLOR_TYP); Begin port[COLOR_REG_WR]:=index; port[COLOR_DATA]:=color.red; port[COLOR_DATA]:=color.green; port[COLOR_DATA]:=color.blue; End; Var VIDEO_BUFFER : Word; gm,index,n: integer; color: RGB_COLOR_TYP; Begin clrscr; VIDEO_BUFFER:=$A000; gm:=$13; set_mode(gm); index:=0; n:=2; Repeat n:=n+b; color.red:=n; color.green:=0; color.blue:=n; write_color_reg(index,color); Delay(150); If n>60 Then b:=-1; If n<4 Then b:=1; Until KeyPressed; gm:=3; (* Text Mode *) set_mode(gm); End.
File đính kèm:
- BAI2.doc