在汇编中打印 bmp 后返回正常的 BIOS 调色板

Returning to the normal BIOS color palette after printing a bmp in assembly

我正在用 8086 汇编(在 DOSBOX 中)开发一个游戏项目。

我有一个可以在图形模式下运行的贪吃蛇游戏,以及一个可以将 BMP 文件打印到屏幕上的菜单。

我唯一的问题是在打印过程中我将调色板更改为 bmp 调色板。

变色过程:

(这是将 bmp 打印到屏幕的代码的一部分)

proc ReadPalette
    ; Read BMP file color palette, 256 colors * 4 bytes (400h)
    mov ah,3fh
    mov cx,400h
    mov dx,offset Palette
    int 21h
    ret
endp ReadPalette

proc CopyPal
    ; Copy the colors palette to the video memory registers
    ; The number of the first color should be sent to port 3C8h
    ; The palette is sent to port 3C9h
    mov si,offset Palette
    mov cx,256
    mov dx,3C8h
    mov al,0
    ; Copy starting color to port 3C8h
    out dx,al
    ; Copy palette itself to port 3C9h
    inc dx
    PalLoop:
        ; Note: Colors in a BMP file are saved as BGR values rather than RGB.
        mov al,[si+2] ; Get red value.
        shr al,2 ; Max. is 255, but video palette maximal
         ; value is 63. Therefore dividing by 4.
        out dx,al ; Send it.
        mov al,[si+1] ; Get green value.
        shr al,2
        out dx,al ; Send it.
        mov al,[si] ; Get blue value.
        shr al,2
        out dx,al ; Send it.
        add si,4 ; Point to next color.
        ; (There is a null chr. after every color.)
        loop PalLoop
    ret
endp CopyPal

这段代码不是我的,我只知道它改变了整个程序的调色板。

当我在打印图像后使用 int 10h 打印像素时,它仍在使用此调色板。

但是当我在打印任何图像之前打印一个像素时,该像素具有正常的 BIOS 颜色。

我想知道如何将调色板改回 BIOS 调色板。

我发现的 bmp 调色板:

您必须在更改之前保存 BIOS 标准调色板,然后在完成后将其存储回去。

执行此操作的示例代码可能是

;WORD Buffer Segment
;WORD Buffer  Offset
;DF = Direction of saving
SavePalette:
push bp
mov bp, sp

push es
push di
push ax
push dx
push cx

mov es, WORD [bp+06h]
mov di, WORD [bp+04h]

xor al, al
mov dx, 3c7h
out dx, al      ;Read from index 0

inc dx
inc dx
mov cx, 300h        ;3x256 reads
rep insb    

pop cx
pop dx
pop ax
pop di
pop es

pop bp
ret 04h


;WORD Buffer Segment
;WORD Buffer  Offset
;DF = Direction of loading
RestorePalette:
push bp
mov bp, sp

push ds
push si
push ax
push dx
push cx

mov ds, WORD [bp+06h]
mov si, WORD [bp+04h]

xor al, al
mov dx, 3c8h
out dx, al      ;Write from index 0

inc dx
mov cx, 300h        ;3x256 writes
rep outsb       

pop cx
pop dx
pop ax
pop si
pop ds

pop bp
ret 04h

要使用此代码,您需要一个 300h 字节的缓冲区,假设它称为 PaletteBuffer 并且位于 DS 段中。

push ds
push WORD PaletteBuffer
call SavePalette

;Change palette for bitmap

push ds
push WORD PaletteBuffer
call RestorePalette

值得注意的是,更改整个调色板很慢,请考虑将代码更改为 save/restore 仅您需要的颜色(可能是前 16 种),或者仅在需要时将位图颜色映射到高索引数量少于256。

这也是 NASM 程序集,我还没有测试代码,只是草拟了一下,因为我不想设置 DosBox。

http://www.cs.cmu.edu/~ralf/files.html -> inter61a.zip -> INTERRUP.A

--------V-101017-----------------------------
INT 10 - VIDEO - READ BLOCK OF DAC REGISTERS (VGA/MCGA)
AX = 1017h
BX = starting palette register
CX = number of palette registers to read
ES:DX -> buffer (3 * CX bytes in size) (see also AX=1012h)
Return: buffer filled with CX red, green and blue triples
SeeAlso: AX=1012h,AX=1015h,INT 62/AX=00A4h

--------V-101012-----------------------------
INT 10 - VIDEO - SET BLOCK OF DAC REGISTERS (VGA/MCGA)
AX = 1012h
BX = starting color register
CX = number of registers to set
ES:DX -> table of 3*CX bytes where each 3 byte group represents one
     byte each of red, green and blue (0-63)
Return: nothing
SeeAlso: AX=1010h,AX=1017h,INT 62/AX=00A5h