db 512 dup(0)
Stack ends
SCREEN_WIDTH_IN_BYTES equ 80
DISPLAY_MEMORY_SEGMENT equ 0a000h
SC_INDEX equ 3c4h ;Sequence Controller Index register
MAP_MASK equ 2 ;index of Map Mask register
GC_INDEX equ 03ceh ;Graphics Controller Index reg
GRAPHICS_MODE equ 5 ;index of Graphics Mode reg
BIT_MASK equ 8 ;index of Bit Mask reg
Data segment para common 'DATA'
;
; Current location of "A" as it is animated across the screen.
;
CurrentX dw ?
CurrentY dw ?
RemainingLength dw ?
;
; Chunky bit-map image of a yellow "A" on a bright blue background
;
AImage label byte
dw 13, 13 ;width, height in pixels
db 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 009h, 099h, 099h, 099h, 099h, 099h, 000h
db 009h, 099h, 099h, 099h, 099h, 099h, 000h
db 009h, 099h, 099h, 0e9h, 099h, 099h, 000h
db 009h, 099h, 09eh, 0eeh, 099h, 099h, 000h
db 009h, 099h, 0eeh, 09eh, 0e9h, 099h, 000h
db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
db 009h, 09eh, 0eeh, 0eeh, 0eeh, 099h, 000h
db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h
db 009h, 099h, 099h, 099h, 099h, 099h, 000h
db 009h, 099h, 099h, 099h, 099h, 099h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h
Data ends
Code segment para public 'CODE'
assume cs:Code, ds:Data
Start proc near
mov ax,Data
mov ds,ax
mov ax,12h
int 10h ;select video mode 10h (640x350)
;
; Prepare for animation.
;
mov [CurrentX],0
mov [CurrentY],200
mov [RemainingLength],600 ;move 600 times
;
; Animate, repeating RemainingLength times. It's unnecessary to erase
; the old image, since the one pixel of blank fringe around the image
; erases the part of the old image not overlapped by the new image.
;
AnimationLoop:
mov bx,[CurrentX]
mov cx,[CurrentY]
mov si,offset AImage
call DrawFromChunkyBitmap ;draw the "A" image
inc [CurrentX] ;move one pixel to the right
mov cx,0 ;delay so we don't move the
DelayLoop: ; image too fast; adjust as
; needed
loop DelayLoop
dec [RemainingLength]
jnz AnimationLoop
;
; Wait for a key before returning to text mode and ending.
;
mov ah,01h
int 21h
mov ax,03h
int 10h
mov ah,4ch
int 21h
Start endp
;
; Draw an image stored in a chunky-bit map into planar VGA/EGA memory
; at the specified location.
;
; Input:
; BX = X screen location at which to draw the upper left corner
; of the image
; CX = Y screen location at which to draw the upper left corner
; of the image
; DS:SI = pointer to chunky image to draw, as follows:
; word at 0: width of image, in pixels
; word at 2: height of image, in pixels
; byte at 4: msb/lsb = first & second chunky pixels,
; repeating for the remainder of the scan line
; of the image, then for all scan lines. Images
; with odd widths have an unused null nibble
; padding each scan line out to a byte width
;
; AX, BX, CX, DX, SI, DI, ES destroyed.
;
DrawFromChunkyBitmap proc near
cld
;
; Select write mode 2.
; 选择写方式2
mov dx,GC_INDEX
mov al,GRAPHICS_MODE
out dx,al
inc dx
mov al,02h
out dx,al
;
; Enable writes to all 4 planes.
;
mov dx,SC_INDEX ;选择时序寄存器
mov al,MAP_MASK
out dx,al ;选择映像屏蔽寄存器(选择那些位面有效)
inc dx
mov al,0fh
out dx,al ;位面全部有效
;
; Point ES:DI to the display memory byte in which the first pixel
; of the image goes, with AH set up as the bit mask to access that
; pixel within the addressed byte.
;
mov ax,SCREEN_WIDTH_IN_BYTES
mul cx ;offset of start of top scan line
mov di,ax
mov cl,bl
and cl,111b
mov ah,80h ;set AH to the bit mask for the
shr ah,cl ; initial pixel
shr bx,1
shr bx,1
shr bx,1 ;X in bytes
add di,bx ;offset of upper left byte of image
mov bx,DISPLAY_MEMORY_SEGMENT
mov es,bx ;ES:DI points to the byte at which the
; upper left of the image goes
;
; Get the width and height of the image.
;
mov cx,[si] ;get the width
inc si
inc si
mov bx,[si] ;get the height
inc si
inc si
mov dx,GC_INDEX ; 选择图像控制寄存器
mov al,BIT_MASK ; 选择位屏蔽寄存器
out dx,al ;leave the GC Index register pointing
inc dx ; to the Bit Mask register
RowLoop: ;行循环
push ax ;preserve the left column's bit mask
push cx ;preserve the width
push di ;preserve the destination offset
ColumnLoop: ;列循环
mov al,ah
out dx,al ;set the bit mask to draw this pixel 为要写的像素设置位掩码
mov al,es:[di] ;load the latches 装载锁存器
mov al,[si] ;get the next two chunky pixels
shr al,1 ;从此行开始到最后一行都不明白
shr al,1
shr al,1
shr al,1 ;move the first pixel into the lsb
stosb ;draw the first pixel
ror ah,1 ;move mask to next pixel position
jc CheckMorePixels ;is next pixel in the adjacent byte? 接下来的像素在相邻字节吗
dec di ;no
CheckMorePixels:
dec cx ;see if there are any more pixels
jz AdvanceToNextScanLine ; across in image
mov al,ah
out dx,al ;set the bit mask to draw this pixel
mov al,es:[di] ;load the latches
lodsb ;get the same two chunky pixels again
stosb ;draw the second of the two pixels
ror ah,1 ;move mask to next pixel position
jc CheckMorePixels2 ;is next pixel in the adjacent byte?
dec di ;no
CheckMorePixels2:
loop ColumnLoop ;see if there are any more pixels
jmp short CheckMoreScanLines
AdvanceToNextScanLine:
inc si ;advance to the start of the next
CheckMoreScanLines:
pop di ;get back the destination offset
pop cx ;get back the width
pop ax ;get back the left column's bit mask
add di,SCREEN_WIDTH_IN_BYTES
dec bx ;see if there are any more scan lines
jnz RowLoop ; in the image
ret
DrawFromChunkyBitmap endp
Code ends
end Start
各位帮帮忙啊
46 个解决方案
#1
运行一下此程序只发现屏幕右"A".
#2
郁闷,我早就知道老
#3
这是VGA,不是EGA。640*480,16色显示模式。16色显示模式显存分为8个位平面映射,也就是一个字节内存映射8个像素点,通过向3CE端口输出08H再向3CF端口输出位平面掩码来切换。向显存输出前必须先读一下以打开映射通道,否则输出无效。因为16色只需要4位数,一个字节可以储存两个像素的值,向显存输出时只有低4位是有效的,连续四个shr al,1就是把高4位移到低4位上,8086没有shr al,4这样的指令。
#4
gz
#5
1:"连续四个shr al,1就是把高4位移到低4位上"
按你这么一说,那我低四位的像素不是被一走了吗?
2:“这是VGA,不是EGA。640*480,16色显示模式。16色显示模式显存分为8个位平面映射,也就是一个字节内存映射8个像素点”
何以见得,代码中的“mov al,0fh”足以说明是是4个位面
按你这么一说,那我低四位的像素不是被一走了吗?
2:“这是VGA,不是EGA。640*480,16色显示模式。16色显示模式显存分为8个位平面映射,也就是一个字节内存映射8个像素点”
何以见得,代码中的“mov al,0fh”足以说明是是4个位面
#6
1、因为Image数据中1字节表示两个像素颜色,高4位与低4位各表示一个像素,右移四位是准备输出高4位,低四位在后面的代码中输出。
2、下面这两行指令是把显示模式设置为640*480,16色:
mov ax,12h
int 10h ;select video mode 10h (640x350)
这个注释信息是错的,如果要640x350,应该ax=10H。
2、下面这两行指令是把显示模式设置为640*480,16色:
mov ax,12h
int 10h ;select video mode 10h (640x350)
这个注释信息是错的,如果要640x350,应该ax=10H。
#7
呵呵,谢谢你"CNZDGS".
我现在有点糊涂,您能不能把多个CPU字节(至少2字节)按写方式2写入各位面(郁闷,具体是几个我不知道!)的过程,以及其分布情况详细的阐述一遍,谢谢
我现在有点糊涂,您能不能把多个CPU字节(至少2字节)按写方式2写入各位面(郁闷,具体是几个我不知道!)的过程,以及其分布情况详细的阐述一遍,谢谢
#8
如果要连续填充同一颜色(如画横线),可以一次写多个位面,对于不同颜色只能一次写一个位面。
分布情况是这样:
A000:0这个字节对应屏幕上最上面一行最左边的8个像素,位面0~7分别对应第0到第7像素;A000:1这个字节对应第8到第15这8个像素,同样是每个位面对应一个像素;……一行排完紧接着排下一行。当你要在屏幕上画一个点(x,y)时,先计算y*640+x,其中640是每行的像素个数,然后除以8,商就是显存映射地址的偏移量,余数是位面代号。
分布情况是这样:
A000:0这个字节对应屏幕上最上面一行最左边的8个像素,位面0~7分别对应第0到第7像素;A000:1这个字节对应第8到第15这8个像素,同样是每个位面对应一个像素;……一行排完紧接着排下一行。当你要在屏幕上画一个点(x,y)时,先计算y*640+x,其中640是每行的像素个数,然后除以8,商就是显存映射地址的偏移量,余数是位面代号。
#9
这就怪了,书上说CPU字节的每个为对应一个位面。如CPU字节0位对应位面0,1位对应位面1,以此类推。另外则是位掩码对各个位面分布情况又是怎么样?????????
现在满脑袋问好,只要能弄懂我多加分就是了
现在满脑袋问好,只要能弄懂我多加分就是了
#10
你说的书上这段话是说读像素,读和写是不同的。不清楚的地方做程序试一下就清楚了。
#11
vga12H是640*480,16色,我以前学过一个vga12的c语言汉字处理程序。后来我用汇编vga12h显示了一个4位的图片,用的是out in,现在忘了,现在这个12h不行了,才16色,现在一般都是256色以上,8位的,16/24/32 位的,所以13h是256色,但分辨太低,我只道的只能用svga显卡,vesa标准,是高分辨,高位深。但现在没有svga卡了,我知道一个dos32a扩展器,qv多媒体播放器,可以显示24位图片。
#12
"如果要连续填充同一颜色(如画横线),可以一次写多个位面,对于不同颜色只能一次写一个位面。"怎么实现
#13
晕,一个颜色4位,那跟一个像素4有什么关系,VGA读取一个像素是以4位为单元吗?
#14
当要画一个点时,用写模式2,根据像素位置确定位面;
当要画一条横线时,用写模式0,同时选择8个位面,这样一次是写入8个点。
读像素是分4次读,每次选择一个位面读出一位数据,再组合到一起。
当要画一条横线时,用写模式0,同时选择8个位面,这样一次是写入8个点。
读像素是分4次读,每次选择一个位面读出一位数据,再组合到一起。
#15
哈哈,头脑终于又清晰多了,老大您能加我QQ吗,我想给你细谈这个问题,这样问题解决起来快些!!!
QQ:305513011
QQ:305513011
#16
我没装各种聊天软件,也没有时间聊,只能偶尔抽空看看贴,有问题就在这问吧。不过这方面的程序我已经很多年都没做过了,很多东西记不太清了。
#17
shr al,1 ;从此行开始到最后一行都不明白
shr al,1
shr al,1
shr al,1 ;move the first pixel into the lsb
stosb ;draw the first pixel
ror ah,1 ;move mask to next pixel position
jc CheckMorePixels ;is next pixel in the adjacent byte? 接下来的像素在相邻字节吗
dec di ;no
CheckMorePixels:
dec cx ;see if there are any more pixels
jz AdvanceToNextScanLine ; across in image
mov al,ah
out dx,al ;set the bit mask to draw this pixel
mov al,es:[di] ;load the latches
lodsb ;get the same two chunky pixels again
stosb ;draw the second of the two pixels
ror ah,1 ;move mask to next pixel position
jc CheckMorePixels2 ;is next pixel in the adjacent byte?
dec di ;no
CheckMorePixels2:
loop ColumnLoop ;see if there are any more pixels
jmp short CheckMoreScanLines
AdvanceToNextScanLine:
inc si ;advance to the start of the next
CheckMoreScanLines:
pop di ;get back the destination offset
pop cx ;get back the width
pop ax ;get back the left column's bit mask
add di,SCREEN_WIDTH_IN_BYTES
dec bx ;see if there are any more scan lines
jnz RowLoop ; in the image
ret
DrawFromChunkyBitmap endp
Code ends
end Start
1:代码的看得想发火了,页面怎么这么难,也不给个好的解释!!!!!!!!!!!!!
cnzdgs您行行好,再多做件对我们这些初学者有益的事,好吗,谢谢了
2:上面的代码对我来说没有一点进展,我不明白他把AImage中的每一字节的后四位舍弃的目的何在,并且你所说八个位面我表示怀疑,因为VGA的源码书上也没有提到任何关于8个位面的显存(也就是640×480*16)。而你所说8位面是指的"640×480*256"
#18
我给给解释一下这段代码:
shr al,1
shr al,1
shr al,1
shr al,1
al中是两个像素,高4位是前1个,低4位后1个。al右移4为,把al中的前1个像素移动到低4位,后1个像素暂时抛弃
stosb
写入前1个像素,此时写入的低4位有效,高4位自动抛弃
ror ah,1
ah中是位面掩码,右移1位,准备切换到下1位面
jc CheckMorePixels
ah的8位数据中只有一个1,其余都是0,从最高位开始向低位移,当这个1移出(循环到最高位同时CF置位时)就表示下一像素应该写入下一字节
dec di
ah中的1未移出则还是当前字节,所以di减1,(因为stosb会使di加1)
CheckMorePixels:
dec cx
减计数器
jz AdvanceToNextScanLine
计数器为0则这行像素画完了
mov al,ah
out dx,al
切换位面
mov al,es:[di]
执行一下读操作,否则无法写入
lodsb
再取出[si]中的值,这次是输出低4位,然后si自动加1,指向下1字节
stosb
写入后1像素,同样是低4位有效,高4位抛弃
ror ah,1
准备切换到下一位面
jc CheckMorePixels2
判断是否ah中的1移出
dec di
ah中的1未移出则下一像素还是这个字节
CheckMorePixels2:
loop ColumnLoop
减计数器并循环
shr al,1
shr al,1
shr al,1
shr al,1
al中是两个像素,高4位是前1个,低4位后1个。al右移4为,把al中的前1个像素移动到低4位,后1个像素暂时抛弃
stosb
写入前1个像素,此时写入的低4位有效,高4位自动抛弃
ror ah,1
ah中是位面掩码,右移1位,准备切换到下1位面
jc CheckMorePixels
ah的8位数据中只有一个1,其余都是0,从最高位开始向低位移,当这个1移出(循环到最高位同时CF置位时)就表示下一像素应该写入下一字节
dec di
ah中的1未移出则还是当前字节,所以di减1,(因为stosb会使di加1)
CheckMorePixels:
dec cx
减计数器
jz AdvanceToNextScanLine
计数器为0则这行像素画完了
mov al,ah
out dx,al
切换位面
mov al,es:[di]
执行一下读操作,否则无法写入
lodsb
再取出[si]中的值,这次是输出低4位,然后si自动加1,指向下1字节
stosb
写入后1像素,同样是低4位有效,高4位抛弃
ror ah,1
准备切换到下一位面
jc CheckMorePixels2
判断是否ah中的1移出
dec di
ah中的1未移出则下一像素还是这个字节
CheckMorePixels2:
loop ColumnLoop
减计数器并循环
#19
对于16色显示模式,在写模式2中,A000段中每个字节对应8个像素,分别在8个位面上,不要把位面与二进制的位联系到一起。
256色比16色简单得多,每个字节就是一个像素,直接读写,只是需要切换显存映射窗口。
256色比16色简单得多,每个字节就是一个像素,直接读写,只是需要切换显存映射窗口。
#20
cnzdgs谢谢你这几天坚持回帖,我发觉我看不懂VGA代码的关键在出现我理解不了。颜色值,像素值,位面,它们之间关系!
颜色值就是像素值吗,颜色值或像素值跟位面的关系?
#21
其实这些名词没有统一的定义,通常说的颜色值就是像素值,如果严格讲起来是这样:颜色值是由红、绿、蓝(R、G、B)三部分组成,每部分用1字节表示,取值范围是0~255;对于256色以下的图象数据,用索引值表示,索引值就是该像素的颜色在调色板中序号(基于0),显存中储存的也是索引值。
位面是从Plane翻译过来的,因为使用某些显示模式时,每个内存地址对应多个显存地址,所以把显存形象化地分成多个平面,每个内存地址在各个平面上都有一个投影,就是映射。至于“位”字,应该是来自于bit mark,在选择Plane是需要输出一个位掩码,每一位对应一个Plane,为1的表示选中,为0的表示屏蔽。
位面是从Plane翻译过来的,因为使用某些显示模式时,每个内存地址对应多个显存地址,所以把显存形象化地分成多个平面,每个内存地址在各个平面上都有一个投影,就是映射。至于“位”字,应该是来自于bit mark,在选择Plane是需要输出一个位掩码,每一位对应一个Plane,为1的表示选中,为0的表示屏蔽。
#22
哦,原来是这样啊,再次感谢。那么通过位掩码码选在一个位例如:bit mark:0001则选择位面0,我通过向该显存地址写一个字节,只有有这个位面才接受四个像素位(颜色),那么VGA通过"读"哪些位面来输入屏幕呢,而且读取是1位还是4位(这跟"读"操作有关吗)
#23
读的时候是4个位面,每个位面包含像素的一位,所以要分4次来读,每读一位切换一次位面,每次读出的数据中只有对应位是有效的,要自己把有效位提取出来。
#24
你真及时啊!!!学习了,从您上面的分析来看,bit mark包含在一字节中,是吧?
#25
对
#26
看了一天的代码,还是没什么收获。一会儿又是4位一个像素,一会儿又一字节一个像素。现在到好彻底的混为一谈了!!
#27
请问您能否在线聊天(WEB)。
#28
我看你是离线状态。
你只要知道:在16色显示模式下,读一个像素是从4个位面各读一位数据;写一个像素是向1个位面写一字节数据(低4位有效)就可以了。
你只要知道:在16色显示模式下,读一个像素是从4个位面各读一位数据;写一个像素是向1个位面写一字节数据(低4位有效)就可以了。
#29
cnzdgs这几天都多亏你的帮忙,我才对VGA有了一定的了解。
#30
不客气。这方面还是要自己做程序去试才能掌握清楚,看别人的代码是比较费劲的。
#31
不知道是不是
CheckMoreScanLines:
pop di ;get back the destination offset
pop cx ;get back the width
pop ax ;get back the left column's bit mask
add di,SCREEN_WIDTH_IN_BYTES ;开始下一扫描线
CheckMoreScanLines:
pop di ;get back the destination offset
pop cx ;get back the width
pop ax ;get back the left column's bit mask
add di,SCREEN_WIDTH_IN_BYTES ;开始下一扫描线
#32
对
#33
.model small
vgaseg equ 0a000h
sequen_ctl equ 3c4h
graphi_ctl equ 3ceh
Onscreen_X equ 20
Onscreen_y equ 100
linelen equ 640/8
only_one_pixel equ 003h
.code
start:
mov ax,vgaseg ;ES段指向显存地址0a000h
mov es,ax
mov cx,0
mov dx,184Fh
mov bh,07
mov ax,600h
int 10h
;没有堆栈
mov ax, 12h
int 10h
mov ax,Onscreen_y
push ax
mov ax,Onscreen_X
push ax
call enable_write_mode_one
enable_write_mode_one proc
mov bp,sp
mov ax,[bp] ;取x
mov cl,3
shr bx,cl ;X0/8
mov ax,[bp+2]
mov cx,linelen
mul cx
add ax,bx ;该坐标所在内存字节
mov di,ax
;设置映象屏蔽寄存器
mov dx,sequen_ctl
mov al,2
out dx,al
inc dx
mov al,0fh ;四个位面全部充许写
out dx,al
;选择写方式2
mov dx,graphi_ctl
mov al,5
out dx,al
inc dx
mov al,2
out dx,al
;计算屏蔽码,并设置位屏蔽寄存器
point: dec dx
mov al,8
out dx,al
mov cx,[bp] ;取出X在一个位面上位置
and cl,7
mov al,80h
shr al,cl
inc dx
out dx,al
ror al,1
jc done
;写数据
mov ax,only_one_pixel ;取颜色值
mov ah,es:[di] ;读一次使屏蔽寄存器有效
mov es:[di],al ;写入显示存储器
mov ax,[bp]
inc ax
mov [bp],ax
jmp point
done:nop
jmp done
enable_write_mode_one endp
end start
从POINT开始我的目的是显示一个点,但结果是一条线
vgaseg equ 0a000h
sequen_ctl equ 3c4h
graphi_ctl equ 3ceh
Onscreen_X equ 20
Onscreen_y equ 100
linelen equ 640/8
only_one_pixel equ 003h
.code
start:
mov ax,vgaseg ;ES段指向显存地址0a000h
mov es,ax
mov cx,0
mov dx,184Fh
mov bh,07
mov ax,600h
int 10h
;没有堆栈
mov ax, 12h
int 10h
mov ax,Onscreen_y
push ax
mov ax,Onscreen_X
push ax
call enable_write_mode_one
enable_write_mode_one proc
mov bp,sp
mov ax,[bp] ;取x
mov cl,3
shr bx,cl ;X0/8
mov ax,[bp+2]
mov cx,linelen
mul cx
add ax,bx ;该坐标所在内存字节
mov di,ax
;设置映象屏蔽寄存器
mov dx,sequen_ctl
mov al,2
out dx,al
inc dx
mov al,0fh ;四个位面全部充许写
out dx,al
;选择写方式2
mov dx,graphi_ctl
mov al,5
out dx,al
inc dx
mov al,2
out dx,al
;计算屏蔽码,并设置位屏蔽寄存器
point: dec dx
mov al,8
out dx,al
mov cx,[bp] ;取出X在一个位面上位置
and cl,7
mov al,80h
shr al,cl
inc dx
out dx,al
ror al,1
jc done
;写数据
mov ax,only_one_pixel ;取颜色值
mov ah,es:[di] ;读一次使屏蔽寄存器有效
mov es:[di],al ;写入显示存储器
mov ax,[bp]
inc ax
mov [bp],ax
jmp point
done:nop
jmp done
enable_write_mode_one endp
end start
从POINT开始我的目的是显示一个点,但结果是一条线
#34
你这是一个循环,把jmp point去掉就是一个点了。另外
ror al,1
jc done
这两行应该去掉。
ror al,1
jc done
这两行应该去掉。
#35
啊,为什么,我按你所说的理解为:一个颜色,进行各位屏蔽后才写入位面,我的那个循环也是这个目的。我那理解错了!
#36
而且像素显示的位置也不对
#37
像素显示的位置这个问题解决了,堆栈处理不当
#38
设置位屏蔽寄存器只需要一次输出,输出的字节中为1的那一位对应位面被选中,其它位面都屏蔽。
#39
还有就是为什么要把X坐标除8,X不是已经是个字节(像素),还是它的这个像素概念是相对于位面???
假设颜色数值是003h(因为有8位,所以有8个像素),即二进制0000011。设x=1,那么x坐标求余为1,相反屏蔽了位6,那么剩下5位,我怎么办了,我通过循环也就是这个目的
假设颜色数值是003h(因为有8位,所以有8个像素),即二进制0000011。设x=1,那么x坐标求余为1,相反屏蔽了位6,那么剩下5位,我怎么办了,我通过循环也就是这个目的
#40
你现在理解的很混乱。
在写模式2下,A000段的每个字节对应的是8个像素,这8个像素各对应一个位面。在写像素之前要通过设置位屏蔽寄存器来控制选择其中1个位面,屏蔽其它7个位面。屏蔽寄存器中的8位二进制数中每1位对应一个位面,为1的位面有效,为0位面屏蔽。
当要写一个像素时,首先根据像素坐标(X,Y),先计算Y*640+X,这是总的像素序号,然后把Y*640+X除以8,商就是该像素在A000段的偏移量(将其保存到DI),余数是位面代号(将其保存到CL),把80H右移CL位,然后输出到位屏蔽寄存器,这样就选中了该像素对应的位面同时屏蔽了其它无关位面,然后把A000:DI的数据先读出一下,再把要写入的像素值写入,这样就完成了。
在写模式2下,A000段的每个字节对应的是8个像素,这8个像素各对应一个位面。在写像素之前要通过设置位屏蔽寄存器来控制选择其中1个位面,屏蔽其它7个位面。屏蔽寄存器中的8位二进制数中每1位对应一个位面,为1的位面有效,为0位面屏蔽。
当要写一个像素时,首先根据像素坐标(X,Y),先计算Y*640+X,这是总的像素序号,然后把Y*640+X除以8,商就是该像素在A000段的偏移量(将其保存到DI),余数是位面代号(将其保存到CL),把80H右移CL位,然后输出到位屏蔽寄存器,这样就选中了该像素对应的位面同时屏蔽了其它无关位面,然后把A000:DI的数据先读出一下,再把要写入的像素值写入,这样就完成了。
#41
我有两本VGA方面的电子版,说的都是很笼统,所以有时候分布清那是对的那是错的。。
1:你的意思是说一个页面有640*480个像素吗。
2:"余数是位面代号(将其保存到CL),把80H右移CL位",这只是单个位面吧,我的意思就是想使用XOR CL,1移动掩码位啊,就像我上面代码那样。
1:你的意思是说一个页面有640*480个像素吗。
2:"余数是位面代号(将其保存到CL),把80H右移CL位",这只是单个位面吧,我的意思就是想使用XOR CL,1移动掩码位啊,就像我上面代码那样。
#42
1、这种显示模式整个屏幕就是640*480个像素;
2、写一个点就是要选一个位面,如果是画线才需要循环切换位面。
2、写一个点就是要选一个位面,如果是画线才需要循环切换位面。
#43
总之,我还是谢谢你这几天回复,的确我被VGA各种操作搞混了,还是专注的看另一本书吧!:-)
#44
|--| ----------------------|
|1 | 0位面的1个字节 |
| | 从最高位开始 |
|--| 每个时钟周期移动一个BIT |
|
|--| |
| 1| 1位面的1个字节 |
| | 从最高位开始 |
|--| 每个时钟周期移动一个BIT |
| 四位颜色值
|
|--| |
| 2| 2位面的1个字节 |
| | 从最高位开始 |
|--| 每个时钟周期移动一个BIT |
|
|--| |
|3 | 3位面的1个字节 |
| | 从最高位开始 |
|--| 每个时钟周期移动一个BIT -------------|
迷糊了,怎么又成一个字节了啊
#45
是不是0~3位面相同位对应一个4位值
#46
跟时钟周期没有关系。
写的时候有8个位面,每个位面中的1字节(只有低4位有效)对应1个像素值。
读的时候有4个位面,4个位面中的同一位对应1个像素值的4位数据。
建议你先做一个写单一像素的函数,可以在屏幕上任意位置画一个点,然后再练习用画点的方式贴图;写单一像素熟悉了之后,再做一个画横线函数,可以在屏幕上任意位置画任意长度的横线,然后再练习画矩形;然后再做一个读单一像素的函数;再做读一个读横线函数,再练习读矩形。到这基本就都掌握了,可以再熟悉其它操作模式。
写的时候有8个位面,每个位面中的1字节(只有低4位有效)对应1个像素值。
读的时候有4个位面,4个位面中的同一位对应1个像素值的4位数据。
建议你先做一个写单一像素的函数,可以在屏幕上任意位置画一个点,然后再练习用画点的方式贴图;写单一像素熟悉了之后,再做一个画横线函数,可以在屏幕上任意位置画任意长度的横线,然后再练习画矩形;然后再做一个读单一像素的函数;再做读一个读横线函数,再练习读矩形。到这基本就都掌握了,可以再熟悉其它操作模式。
#1
运行一下此程序只发现屏幕右"A".
#2
郁闷,我早就知道老
#3
这是VGA,不是EGA。640*480,16色显示模式。16色显示模式显存分为8个位平面映射,也就是一个字节内存映射8个像素点,通过向3CE端口输出08H再向3CF端口输出位平面掩码来切换。向显存输出前必须先读一下以打开映射通道,否则输出无效。因为16色只需要4位数,一个字节可以储存两个像素的值,向显存输出时只有低4位是有效的,连续四个shr al,1就是把高4位移到低4位上,8086没有shr al,4这样的指令。
#4
gz
#5
1:"连续四个shr al,1就是把高4位移到低4位上"
按你这么一说,那我低四位的像素不是被一走了吗?
2:“这是VGA,不是EGA。640*480,16色显示模式。16色显示模式显存分为8个位平面映射,也就是一个字节内存映射8个像素点”
何以见得,代码中的“mov al,0fh”足以说明是是4个位面
按你这么一说,那我低四位的像素不是被一走了吗?
2:“这是VGA,不是EGA。640*480,16色显示模式。16色显示模式显存分为8个位平面映射,也就是一个字节内存映射8个像素点”
何以见得,代码中的“mov al,0fh”足以说明是是4个位面
#6
1、因为Image数据中1字节表示两个像素颜色,高4位与低4位各表示一个像素,右移四位是准备输出高4位,低四位在后面的代码中输出。
2、下面这两行指令是把显示模式设置为640*480,16色:
mov ax,12h
int 10h ;select video mode 10h (640x350)
这个注释信息是错的,如果要640x350,应该ax=10H。
2、下面这两行指令是把显示模式设置为640*480,16色:
mov ax,12h
int 10h ;select video mode 10h (640x350)
这个注释信息是错的,如果要640x350,应该ax=10H。
#7
呵呵,谢谢你"CNZDGS".
我现在有点糊涂,您能不能把多个CPU字节(至少2字节)按写方式2写入各位面(郁闷,具体是几个我不知道!)的过程,以及其分布情况详细的阐述一遍,谢谢
我现在有点糊涂,您能不能把多个CPU字节(至少2字节)按写方式2写入各位面(郁闷,具体是几个我不知道!)的过程,以及其分布情况详细的阐述一遍,谢谢
#8
如果要连续填充同一颜色(如画横线),可以一次写多个位面,对于不同颜色只能一次写一个位面。
分布情况是这样:
A000:0这个字节对应屏幕上最上面一行最左边的8个像素,位面0~7分别对应第0到第7像素;A000:1这个字节对应第8到第15这8个像素,同样是每个位面对应一个像素;……一行排完紧接着排下一行。当你要在屏幕上画一个点(x,y)时,先计算y*640+x,其中640是每行的像素个数,然后除以8,商就是显存映射地址的偏移量,余数是位面代号。
分布情况是这样:
A000:0这个字节对应屏幕上最上面一行最左边的8个像素,位面0~7分别对应第0到第7像素;A000:1这个字节对应第8到第15这8个像素,同样是每个位面对应一个像素;……一行排完紧接着排下一行。当你要在屏幕上画一个点(x,y)时,先计算y*640+x,其中640是每行的像素个数,然后除以8,商就是显存映射地址的偏移量,余数是位面代号。
#9
这就怪了,书上说CPU字节的每个为对应一个位面。如CPU字节0位对应位面0,1位对应位面1,以此类推。另外则是位掩码对各个位面分布情况又是怎么样?????????
现在满脑袋问好,只要能弄懂我多加分就是了
现在满脑袋问好,只要能弄懂我多加分就是了
#10
你说的书上这段话是说读像素,读和写是不同的。不清楚的地方做程序试一下就清楚了。
#11
vga12H是640*480,16色,我以前学过一个vga12的c语言汉字处理程序。后来我用汇编vga12h显示了一个4位的图片,用的是out in,现在忘了,现在这个12h不行了,才16色,现在一般都是256色以上,8位的,16/24/32 位的,所以13h是256色,但分辨太低,我只道的只能用svga显卡,vesa标准,是高分辨,高位深。但现在没有svga卡了,我知道一个dos32a扩展器,qv多媒体播放器,可以显示24位图片。
#12
"如果要连续填充同一颜色(如画横线),可以一次写多个位面,对于不同颜色只能一次写一个位面。"怎么实现
#13
晕,一个颜色4位,那跟一个像素4有什么关系,VGA读取一个像素是以4位为单元吗?
#14
当要画一个点时,用写模式2,根据像素位置确定位面;
当要画一条横线时,用写模式0,同时选择8个位面,这样一次是写入8个点。
读像素是分4次读,每次选择一个位面读出一位数据,再组合到一起。
当要画一条横线时,用写模式0,同时选择8个位面,这样一次是写入8个点。
读像素是分4次读,每次选择一个位面读出一位数据,再组合到一起。
#15
哈哈,头脑终于又清晰多了,老大您能加我QQ吗,我想给你细谈这个问题,这样问题解决起来快些!!!
QQ:305513011
QQ:305513011
#16
我没装各种聊天软件,也没有时间聊,只能偶尔抽空看看贴,有问题就在这问吧。不过这方面的程序我已经很多年都没做过了,很多东西记不太清了。
#17
shr al,1 ;从此行开始到最后一行都不明白
shr al,1
shr al,1
shr al,1 ;move the first pixel into the lsb
stosb ;draw the first pixel
ror ah,1 ;move mask to next pixel position
jc CheckMorePixels ;is next pixel in the adjacent byte? 接下来的像素在相邻字节吗
dec di ;no
CheckMorePixels:
dec cx ;see if there are any more pixels
jz AdvanceToNextScanLine ; across in image
mov al,ah
out dx,al ;set the bit mask to draw this pixel
mov al,es:[di] ;load the latches
lodsb ;get the same two chunky pixels again
stosb ;draw the second of the two pixels
ror ah,1 ;move mask to next pixel position
jc CheckMorePixels2 ;is next pixel in the adjacent byte?
dec di ;no
CheckMorePixels2:
loop ColumnLoop ;see if there are any more pixels
jmp short CheckMoreScanLines
AdvanceToNextScanLine:
inc si ;advance to the start of the next
CheckMoreScanLines:
pop di ;get back the destination offset
pop cx ;get back the width
pop ax ;get back the left column's bit mask
add di,SCREEN_WIDTH_IN_BYTES
dec bx ;see if there are any more scan lines
jnz RowLoop ; in the image
ret
DrawFromChunkyBitmap endp
Code ends
end Start
1:代码的看得想发火了,页面怎么这么难,也不给个好的解释!!!!!!!!!!!!!
cnzdgs您行行好,再多做件对我们这些初学者有益的事,好吗,谢谢了
2:上面的代码对我来说没有一点进展,我不明白他把AImage中的每一字节的后四位舍弃的目的何在,并且你所说八个位面我表示怀疑,因为VGA的源码书上也没有提到任何关于8个位面的显存(也就是640×480*16)。而你所说8位面是指的"640×480*256"
#18
我给给解释一下这段代码:
shr al,1
shr al,1
shr al,1
shr al,1
al中是两个像素,高4位是前1个,低4位后1个。al右移4为,把al中的前1个像素移动到低4位,后1个像素暂时抛弃
stosb
写入前1个像素,此时写入的低4位有效,高4位自动抛弃
ror ah,1
ah中是位面掩码,右移1位,准备切换到下1位面
jc CheckMorePixels
ah的8位数据中只有一个1,其余都是0,从最高位开始向低位移,当这个1移出(循环到最高位同时CF置位时)就表示下一像素应该写入下一字节
dec di
ah中的1未移出则还是当前字节,所以di减1,(因为stosb会使di加1)
CheckMorePixels:
dec cx
减计数器
jz AdvanceToNextScanLine
计数器为0则这行像素画完了
mov al,ah
out dx,al
切换位面
mov al,es:[di]
执行一下读操作,否则无法写入
lodsb
再取出[si]中的值,这次是输出低4位,然后si自动加1,指向下1字节
stosb
写入后1像素,同样是低4位有效,高4位抛弃
ror ah,1
准备切换到下一位面
jc CheckMorePixels2
判断是否ah中的1移出
dec di
ah中的1未移出则下一像素还是这个字节
CheckMorePixels2:
loop ColumnLoop
减计数器并循环
shr al,1
shr al,1
shr al,1
shr al,1
al中是两个像素,高4位是前1个,低4位后1个。al右移4为,把al中的前1个像素移动到低4位,后1个像素暂时抛弃
stosb
写入前1个像素,此时写入的低4位有效,高4位自动抛弃
ror ah,1
ah中是位面掩码,右移1位,准备切换到下1位面
jc CheckMorePixels
ah的8位数据中只有一个1,其余都是0,从最高位开始向低位移,当这个1移出(循环到最高位同时CF置位时)就表示下一像素应该写入下一字节
dec di
ah中的1未移出则还是当前字节,所以di减1,(因为stosb会使di加1)
CheckMorePixels:
dec cx
减计数器
jz AdvanceToNextScanLine
计数器为0则这行像素画完了
mov al,ah
out dx,al
切换位面
mov al,es:[di]
执行一下读操作,否则无法写入
lodsb
再取出[si]中的值,这次是输出低4位,然后si自动加1,指向下1字节
stosb
写入后1像素,同样是低4位有效,高4位抛弃
ror ah,1
准备切换到下一位面
jc CheckMorePixels2
判断是否ah中的1移出
dec di
ah中的1未移出则下一像素还是这个字节
CheckMorePixels2:
loop ColumnLoop
减计数器并循环
#19
对于16色显示模式,在写模式2中,A000段中每个字节对应8个像素,分别在8个位面上,不要把位面与二进制的位联系到一起。
256色比16色简单得多,每个字节就是一个像素,直接读写,只是需要切换显存映射窗口。
256色比16色简单得多,每个字节就是一个像素,直接读写,只是需要切换显存映射窗口。
#20
cnzdgs谢谢你这几天坚持回帖,我发觉我看不懂VGA代码的关键在出现我理解不了。颜色值,像素值,位面,它们之间关系!
颜色值就是像素值吗,颜色值或像素值跟位面的关系?
#21
其实这些名词没有统一的定义,通常说的颜色值就是像素值,如果严格讲起来是这样:颜色值是由红、绿、蓝(R、G、B)三部分组成,每部分用1字节表示,取值范围是0~255;对于256色以下的图象数据,用索引值表示,索引值就是该像素的颜色在调色板中序号(基于0),显存中储存的也是索引值。
位面是从Plane翻译过来的,因为使用某些显示模式时,每个内存地址对应多个显存地址,所以把显存形象化地分成多个平面,每个内存地址在各个平面上都有一个投影,就是映射。至于“位”字,应该是来自于bit mark,在选择Plane是需要输出一个位掩码,每一位对应一个Plane,为1的表示选中,为0的表示屏蔽。
位面是从Plane翻译过来的,因为使用某些显示模式时,每个内存地址对应多个显存地址,所以把显存形象化地分成多个平面,每个内存地址在各个平面上都有一个投影,就是映射。至于“位”字,应该是来自于bit mark,在选择Plane是需要输出一个位掩码,每一位对应一个Plane,为1的表示选中,为0的表示屏蔽。
#22
哦,原来是这样啊,再次感谢。那么通过位掩码码选在一个位例如:bit mark:0001则选择位面0,我通过向该显存地址写一个字节,只有有这个位面才接受四个像素位(颜色),那么VGA通过"读"哪些位面来输入屏幕呢,而且读取是1位还是4位(这跟"读"操作有关吗)
#23
读的时候是4个位面,每个位面包含像素的一位,所以要分4次来读,每读一位切换一次位面,每次读出的数据中只有对应位是有效的,要自己把有效位提取出来。
#24
你真及时啊!!!学习了,从您上面的分析来看,bit mark包含在一字节中,是吧?
#25
对
#26
看了一天的代码,还是没什么收获。一会儿又是4位一个像素,一会儿又一字节一个像素。现在到好彻底的混为一谈了!!
#27
请问您能否在线聊天(WEB)。
#28
我看你是离线状态。
你只要知道:在16色显示模式下,读一个像素是从4个位面各读一位数据;写一个像素是向1个位面写一字节数据(低4位有效)就可以了。
你只要知道:在16色显示模式下,读一个像素是从4个位面各读一位数据;写一个像素是向1个位面写一字节数据(低4位有效)就可以了。
#29
cnzdgs这几天都多亏你的帮忙,我才对VGA有了一定的了解。
#30
不客气。这方面还是要自己做程序去试才能掌握清楚,看别人的代码是比较费劲的。
#31
不知道是不是
CheckMoreScanLines:
pop di ;get back the destination offset
pop cx ;get back the width
pop ax ;get back the left column's bit mask
add di,SCREEN_WIDTH_IN_BYTES ;开始下一扫描线
CheckMoreScanLines:
pop di ;get back the destination offset
pop cx ;get back the width
pop ax ;get back the left column's bit mask
add di,SCREEN_WIDTH_IN_BYTES ;开始下一扫描线
#32
对
#33
.model small
vgaseg equ 0a000h
sequen_ctl equ 3c4h
graphi_ctl equ 3ceh
Onscreen_X equ 20
Onscreen_y equ 100
linelen equ 640/8
only_one_pixel equ 003h
.code
start:
mov ax,vgaseg ;ES段指向显存地址0a000h
mov es,ax
mov cx,0
mov dx,184Fh
mov bh,07
mov ax,600h
int 10h
;没有堆栈
mov ax, 12h
int 10h
mov ax,Onscreen_y
push ax
mov ax,Onscreen_X
push ax
call enable_write_mode_one
enable_write_mode_one proc
mov bp,sp
mov ax,[bp] ;取x
mov cl,3
shr bx,cl ;X0/8
mov ax,[bp+2]
mov cx,linelen
mul cx
add ax,bx ;该坐标所在内存字节
mov di,ax
;设置映象屏蔽寄存器
mov dx,sequen_ctl
mov al,2
out dx,al
inc dx
mov al,0fh ;四个位面全部充许写
out dx,al
;选择写方式2
mov dx,graphi_ctl
mov al,5
out dx,al
inc dx
mov al,2
out dx,al
;计算屏蔽码,并设置位屏蔽寄存器
point: dec dx
mov al,8
out dx,al
mov cx,[bp] ;取出X在一个位面上位置
and cl,7
mov al,80h
shr al,cl
inc dx
out dx,al
ror al,1
jc done
;写数据
mov ax,only_one_pixel ;取颜色值
mov ah,es:[di] ;读一次使屏蔽寄存器有效
mov es:[di],al ;写入显示存储器
mov ax,[bp]
inc ax
mov [bp],ax
jmp point
done:nop
jmp done
enable_write_mode_one endp
end start
从POINT开始我的目的是显示一个点,但结果是一条线
vgaseg equ 0a000h
sequen_ctl equ 3c4h
graphi_ctl equ 3ceh
Onscreen_X equ 20
Onscreen_y equ 100
linelen equ 640/8
only_one_pixel equ 003h
.code
start:
mov ax,vgaseg ;ES段指向显存地址0a000h
mov es,ax
mov cx,0
mov dx,184Fh
mov bh,07
mov ax,600h
int 10h
;没有堆栈
mov ax, 12h
int 10h
mov ax,Onscreen_y
push ax
mov ax,Onscreen_X
push ax
call enable_write_mode_one
enable_write_mode_one proc
mov bp,sp
mov ax,[bp] ;取x
mov cl,3
shr bx,cl ;X0/8
mov ax,[bp+2]
mov cx,linelen
mul cx
add ax,bx ;该坐标所在内存字节
mov di,ax
;设置映象屏蔽寄存器
mov dx,sequen_ctl
mov al,2
out dx,al
inc dx
mov al,0fh ;四个位面全部充许写
out dx,al
;选择写方式2
mov dx,graphi_ctl
mov al,5
out dx,al
inc dx
mov al,2
out dx,al
;计算屏蔽码,并设置位屏蔽寄存器
point: dec dx
mov al,8
out dx,al
mov cx,[bp] ;取出X在一个位面上位置
and cl,7
mov al,80h
shr al,cl
inc dx
out dx,al
ror al,1
jc done
;写数据
mov ax,only_one_pixel ;取颜色值
mov ah,es:[di] ;读一次使屏蔽寄存器有效
mov es:[di],al ;写入显示存储器
mov ax,[bp]
inc ax
mov [bp],ax
jmp point
done:nop
jmp done
enable_write_mode_one endp
end start
从POINT开始我的目的是显示一个点,但结果是一条线
#34
你这是一个循环,把jmp point去掉就是一个点了。另外
ror al,1
jc done
这两行应该去掉。
ror al,1
jc done
这两行应该去掉。
#35
啊,为什么,我按你所说的理解为:一个颜色,进行各位屏蔽后才写入位面,我的那个循环也是这个目的。我那理解错了!
#36
而且像素显示的位置也不对
#37
像素显示的位置这个问题解决了,堆栈处理不当
#38
设置位屏蔽寄存器只需要一次输出,输出的字节中为1的那一位对应位面被选中,其它位面都屏蔽。
#39
还有就是为什么要把X坐标除8,X不是已经是个字节(像素),还是它的这个像素概念是相对于位面???
假设颜色数值是003h(因为有8位,所以有8个像素),即二进制0000011。设x=1,那么x坐标求余为1,相反屏蔽了位6,那么剩下5位,我怎么办了,我通过循环也就是这个目的
假设颜色数值是003h(因为有8位,所以有8个像素),即二进制0000011。设x=1,那么x坐标求余为1,相反屏蔽了位6,那么剩下5位,我怎么办了,我通过循环也就是这个目的
#40
你现在理解的很混乱。
在写模式2下,A000段的每个字节对应的是8个像素,这8个像素各对应一个位面。在写像素之前要通过设置位屏蔽寄存器来控制选择其中1个位面,屏蔽其它7个位面。屏蔽寄存器中的8位二进制数中每1位对应一个位面,为1的位面有效,为0位面屏蔽。
当要写一个像素时,首先根据像素坐标(X,Y),先计算Y*640+X,这是总的像素序号,然后把Y*640+X除以8,商就是该像素在A000段的偏移量(将其保存到DI),余数是位面代号(将其保存到CL),把80H右移CL位,然后输出到位屏蔽寄存器,这样就选中了该像素对应的位面同时屏蔽了其它无关位面,然后把A000:DI的数据先读出一下,再把要写入的像素值写入,这样就完成了。
在写模式2下,A000段的每个字节对应的是8个像素,这8个像素各对应一个位面。在写像素之前要通过设置位屏蔽寄存器来控制选择其中1个位面,屏蔽其它7个位面。屏蔽寄存器中的8位二进制数中每1位对应一个位面,为1的位面有效,为0位面屏蔽。
当要写一个像素时,首先根据像素坐标(X,Y),先计算Y*640+X,这是总的像素序号,然后把Y*640+X除以8,商就是该像素在A000段的偏移量(将其保存到DI),余数是位面代号(将其保存到CL),把80H右移CL位,然后输出到位屏蔽寄存器,这样就选中了该像素对应的位面同时屏蔽了其它无关位面,然后把A000:DI的数据先读出一下,再把要写入的像素值写入,这样就完成了。
#41
我有两本VGA方面的电子版,说的都是很笼统,所以有时候分布清那是对的那是错的。。
1:你的意思是说一个页面有640*480个像素吗。
2:"余数是位面代号(将其保存到CL),把80H右移CL位",这只是单个位面吧,我的意思就是想使用XOR CL,1移动掩码位啊,就像我上面代码那样。
1:你的意思是说一个页面有640*480个像素吗。
2:"余数是位面代号(将其保存到CL),把80H右移CL位",这只是单个位面吧,我的意思就是想使用XOR CL,1移动掩码位啊,就像我上面代码那样。
#42
1、这种显示模式整个屏幕就是640*480个像素;
2、写一个点就是要选一个位面,如果是画线才需要循环切换位面。
2、写一个点就是要选一个位面,如果是画线才需要循环切换位面。
#43
总之,我还是谢谢你这几天回复,的确我被VGA各种操作搞混了,还是专注的看另一本书吧!:-)
#44
|--| ----------------------|
|1 | 0位面的1个字节 |
| | 从最高位开始 |
|--| 每个时钟周期移动一个BIT |
|
|--| |
| 1| 1位面的1个字节 |
| | 从最高位开始 |
|--| 每个时钟周期移动一个BIT |
| 四位颜色值
|
|--| |
| 2| 2位面的1个字节 |
| | 从最高位开始 |
|--| 每个时钟周期移动一个BIT |
|
|--| |
|3 | 3位面的1个字节 |
| | 从最高位开始 |
|--| 每个时钟周期移动一个BIT -------------|
迷糊了,怎么又成一个字节了啊
#45
是不是0~3位面相同位对应一个4位值
#46
跟时钟周期没有关系。
写的时候有8个位面,每个位面中的1字节(只有低4位有效)对应1个像素值。
读的时候有4个位面,4个位面中的同一位对应1个像素值的4位数据。
建议你先做一个写单一像素的函数,可以在屏幕上任意位置画一个点,然后再练习用画点的方式贴图;写单一像素熟悉了之后,再做一个画横线函数,可以在屏幕上任意位置画任意长度的横线,然后再练习画矩形;然后再做一个读单一像素的函数;再做读一个读横线函数,再练习读矩形。到这基本就都掌握了,可以再熟悉其它操作模式。
写的时候有8个位面,每个位面中的1字节(只有低4位有效)对应1个像素值。
读的时候有4个位面,4个位面中的同一位对应1个像素值的4位数据。
建议你先做一个写单一像素的函数,可以在屏幕上任意位置画一个点,然后再练习用画点的方式贴图;写单一像素熟悉了之后,再做一个画横线函数,可以在屏幕上任意位置画任意长度的横线,然后再练习画矩形;然后再做一个读单一像素的函数;再做读一个读横线函数,再练习读矩形。到这基本就都掌握了,可以再熟悉其它操作模式。