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;

 

doc23 trang | Chia sẻ: hienduc166 | Lượt xem: 696 | Lượt tải: 0download
Bạn đang xem trước 20 trang tài liệu 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, để xem tài liệu hoàn chỉnh bạn click vào nút TẢI VỀ ở trên
 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:

  • docBAI2.doc