16ビットアセンブリを使用してbmpを表示


(November 18 th,2013に書いてあります)
ゲームは16ビットを使って1つのゲームを書くことが要求されているので、画像を表示できればもっと良いと考え始めました.
256色のビットマップを表示する方法をいろいろ探したが,64 kを超えるデータセグメントの防止は結局使用されなかった.やはり記念に書いておきましょう.
   
まず、bmpファイルの構造を理解する必要があります.次に、bmp(ビットマップ)構造体について説明します.
1.BMPファイル構成
BMPファイルは、ファイルヘッダ、ビットマップ情報ヘッダ、色情報、グラフィックデータの4つの部分から構成される.
2.BMPファイルヘッダ(14バイト)
BMPヘッダデータ構造には、BMPファイルの種類、ファイルサイズ、ビットマップの開始位置などの情報が含まれている.
構造は次のように定義されます.
typedef struct tagBITMAPFILEHEADER
 {
     WORD bfType; //        ,   BM(1-2  )
     DWORD bfSize; //        ,      (3-6  )
     WORD bfReserved1; //        ,   0(7-8  )
     WORD bfReserved2; //        ,   0(9-10  )
     DWORD bfOffBits; //          ,      (11-14  )
     //          ,      
 } BITMAPFILEHEADER;

3.ビットマップ情報ヘッダ(40バイト)
BMPビットマップ情報ヘッダデータは、ビットマップのサイズ等を説明するための情報である.
typedef struct tagBITMAPINFOHEADER{
     DWORD biSize; //          (15-18  )
     LONG biWidth; //      ,      (19-22  )
     LONG biHeight; //      ,      (23-26  )
     WORD biPlanes; //        ,   1(27-28  )
     WORD biBitCount;//          ,   1(  ),(29-30  )
     // 4(16 ),8(256 )16(   ) 24(   )  
     DWORD biCompression; //       ,    0(   ),(31-34  )
     // 1(BI_RLE8    ) 2(BI_RLE4    )  
     DWORD biSizeImage; //      ,      (35-38  )
     LONG biXPelsPerMeter; //        ,     (39-42  )
     LONG biYPelsPerMeter; //        ,     (43-46  )
     DWORD biClrUsed;//                (47-50  )
     DWORD biClrImportant;//              (51-54  )
 } BITMAPINFOHEADER;

4.カラーテーブル
カラーテーブルは、ビットマップのカラーを説明するために使用されます.いくつかのテーブルアイテムがあり、各テーブルアイテムはRGBQUADタイプの構造であり、カラーを定義します.RGBQUAD構造の定義は以下の通りである.
typedef struct tagRGBQUAD {
     BYTE rgbBlue;//      (    0-255)
     BYTE rgbGreen; //      (    0-255)
     BYTE rgbRed; //      (    0-255)
     BYTE rgbReserved;//   ,   0
 } RGBQUAD;

カラーテーブルのRGBQUAD構造データの個数はbiBitCountで決定する:
biBitCount=1,4,8の場合、それぞれ2,16256個のテーブル項目がある.
biBitCount=24の場合、カラーテーブル項目はありません.
ビットマップ情報ヘッダとカラーテーブルはビットマップ情報を構成し、BITMAPINFO構造は以下のように定義される.
typedef struct tagBITMAPINFO {
     BITMAPINFOHEADER bmiHeader; //      
     RGBQUAD bmiColors[1]; //    
 } BITMAPINFO;

5.ビットマップデータ
ビットマップデータは、ビットマップの各画素値を記録し、記録順序は、スキャンライン内で左から右、スキャンライン間で下から上である.ビットマップのピクセル値のバイト数:
biBitCount=1の場合、8画素が1バイトを占める.
biBitCount=4の場合、2画素が1バイトを占める.
biBitCount=8の場合、1画素が1バイトを占める.
biBitCount=24の場合、1画素が3バイトを占める.
Windowsでは、スキャン行のバイト数を指定します.
4の倍数(すなわちlong単位)で、不足しているものは0で充填し、
biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

次のコードは、表示するためにアセンブリされます.
320*200

256
カラービットマップの例:
;------------------------------------------------------------------------------------------
;      
data segment
    pathname db '1.bmp', 00    ;     
    x0 dw 0
    y0 dw 0          
    handle dw ?                ;     
    bmpdata1 db 256*4 dup(?)   ;          
    bmpdata2 db 64000 dup(0)   ;       
    bmpwidth dw ?              ;     
    bmplength dw ?          ;     
    pelsnum dw ?               ; temp num
    num dw ?
    flag dw ?                  ; scren set
    screnwidth dw 320
    screnlength dw 200
data ends
                        
;stack
stack1 segment stack
       dw 100h dup(?)
stack1 ends
                        
; code
prognam segment
    assume cs:prognam, ds:data, ss:stack1
main proc far
    ; main part of the program
    mov ax, data
    mov ds, ax
                            
    call openf
    call getinfo
    call readf
    call dispy1
    call dispy2
main endp
                        
;---------------------------------------------------
;        handle    
openf proc near
    lea dx, pathname        
    ; ah = 3dh,al = 0        ,    AX
    mov ah, 3dh
    mov al, 0
    int 21h
    mov handle, ax
    ret
openf endp
                        
;--------------------------------------------------
;         
getinfo proc near
        ;       ,bx =     , cx:dx =    , al = 0         
        mov ah, 42h
        mov al, 0
        mov bx, handle
        mov cx, 0
        mov dx, 12h     ;   18              
        int 21h
        ;     ,ds:dx =        , bx =     , cx =       , ax = 0       
        mov ah, 3fh
        lea dx, bmpwidth        ;       
        mov cx, 2
        int 21h
        mov ah, 42h
        mov al, 0
        mov bx, handle
        mov cx, 0
        mov dx, 16h     ;   22              
        int 21h
        mov ah, 3fh
        lea dx, bmplength       ;       
        mov cx, 2
        int 21h
        mov ax, bmpwidth
        mul bmplength
        mov pelsnum, ax         ;          pelsnum 
        ret
getinfo endp
                        
;---------------------------------------------------
;         
readf proc near
        ;    54         
        mov ah, 42h
        mov al, 0
        mov bx, handle
        mov cx, 0
        mov dx, 36h   
        int 21h
        mov ah, 3fh
        lea dx, bmpdata1        ;        bmpdata1
        mov cx, 256*4           ;  + + +    (0)   256*4   
        int 21h
        ret
readf endp
                        
;-------------------------------------------------------
;display   
dispy1 proc near
       ;   256 ,320*200  
       mov ax, 0013h
       int 10h
       ;              rgb    256 
       mov cx, 256
       lea si, bmpdata1         ;     
p:
       mov dx, 3c8h             ;   i/o  
       mov ax, cx
       dec ax
       neg ax                   ;   
       add ax, 255              ; ax = ffffh(al = ffh, ah = ffh)
       out dx, al               ;  al      dx   i/o   
       inc dx
       ; bmp       :bgr~bgr~...(~  00h)
       ; rgb/4   ,    ,rgb  (0~63),   (0~255)
       mov al, [si+2]           
       shr al, 1              
       shr al, 1
       out dx, al
       mov al, [si+1]
       shr al, 1
       shr al, 1
       out dx, al
       mov al, [si]
       shr al, 1
       shr al, 1
       out dx, al
       add si, 4
       loop p
       ret
dispy1 endp
                        
;--------------------------------------------------
dispy2 proc near
        mov bx, 0a000h          ; 40k
        mov es, bx
dp30:
        mov di, 0
        cld                     ; df  
        mov cx, y0              ; cx = 0
dp00:
        mov ax, bmpwidth        ; ax =     
        mov dx, ax
        and dx, 11b
        jz dp000
        mov ax, 4
        sub ax, dx
        add ax, bmpwidth
dp000:
        inc cx
        mul cx
        dec cx
        mov bx, 0
        sub bx, ax
        mov ax, bx
        mov bx, 0
        sbb bx, dx
        mov dx, bx
        push cx
        mov cx, dx
        mov dx, ax
        mov bx, handle
        mov ax, 4202h
        int 21h
        mov dx, offset bmpdata2
        mov cx, bmpwidth
        mov ah, 3fh
        int 21h
        pop cx
        cmp ax, bmpwidth
        jb dp3
        mov si, offset bmpdata2
        add si, x0
dp0:
        push di
        mov dx, 0 
dp1:
        lodsb
        stosb
        inc dx
        cmp dx, 320
        jae dp2
        push dx
        add dx, x0
        cmp dx, bmpwidth
        pop dx
        jb dp1
dp2:
        pop di
        add di, 320
        inc cx
        push cx
        sub cx, y0
        cmp cx, 200
        pop cx
        jae dp3
        push cx
        cmp cx, bmplength
        pop cx
        jb dp00 
dp3:
        mov ah,0
        int 16h
        cmp ax, 4800h
        je up
        cmp ax, 4b00h
        je left
        cmp ax, 4d00h
        je right
        cmp ax, 5000h
        je down
        cmp ax, 011bh
        je exit
        jmp dp3
up:
        mov ax, y0
        sub ax, 1
        jl dp3
        mov y0, ax
        jmp dp30
down:
        mov ax, y0
        add ax, 1
        push ax
        add ax, 200
        cmp ax, bmplength
        pop ax
        jae dp3
        mov y0,ax
        jmp dp30
left:
        mov ax, x0
        sub ax, 1
        jl dp3
        mov x0, ax
        jmp dp30
right:
        mov ax, x0
        add ax, 1
        push ax
        add ax, 320
        cmp ax, bmpwidth
        pop ax
        jae dp3
        mov x0, ax
        jmp dp30
                        
exit:
        mov ax, 3
        int 10h
        mov ax, 4c00h
        int 21h
xp1:
        mov ax, bmplength
        mul screnwidth
        mov num, ax
        lea si, bmpdata2
        mov cx, bmpwidth
        push cx
        mov ax, bmplength
        mov flag, ax
        dec flag
        sub num, 320
        mov di, num
                        
        add di, 320
        add di, bmpwidth
l2:
        sub di, 320
        sub di, bmpwidth
        cmp flag, 0
        jz l3
        dec flag
        pop cx
        push cx
dis:
        mov al, [si]
        mov ah, 0
        stosb
        add si, 1
        cmp cx, 1
        jz l2
        loop dis
l3:
        mov ah, 0
        int 16h
        mov ax, 3
        int 10h
        mov ax, 4c00h
        int 21h
dispy2 endp
                        
prognam ends    
end main

dosboxでの表示効果:
 
(画像を256色に処理するので、原図に対して少し歪んでいる可能性があります)