Как прочитать файл изображения и отобразить на экране в Windows tasm dosbox

В настоящее время я изучаю графическое программирование в tasm, используя dosbox. Я использовал кучу циклов для рисования квадратных блоков пикселей, и это действительно сложно. Я хочу знать, есть ли способ прочитать изображение и отобразить его. Я знаю, как читать текстовый файл, может быть, это начало. Пожалуйста, помогите


person Jhon Paul Jaspe    schedule 20.08.2017    source источник
comment
Нет, это невозможно... вот почему все DOS-игры рисовали только квадраты, и никогда не было никаких графических файлов с изображениями... /сарказм... да, вы просто загружаете содержимое файла в память, если это сжатый файл, то вы распаковываете его (написать собственный декодер gif может быть намного сложнее, чем делать кучу циклов), а затем копируете его в VRAM. Управление памятью (как вы в реальном режиме? Таким образом, каждая страница памяти имеет длину всего 64 КБ и постоянно жонглирует сегментными регистрами), а также проблемы с палитрой. (вероятно, самый простой способ - подготовить необработанные данные в файле в целевом формате)   -  person Ped7g    schedule 20.08.2017
comment
кстати, я помечаю это как слишком широкое ... вы должны, по крайней мере, выбрать графический режим (16 цветов имеют совершенно другой формат, чем 256 13-часовой режим), указать реальный/защищенный режим (и если вы находитесь в реальном режиме и планируете делать что-либо, интенсивно использующее память, а затем рассмотреть возможность использования какого-либо расширителя, такого как dos4gw, и начать использовать защищенный режим), и указать формат файла gfx (выбирайте с умом, поскольку написание подпрограмм распаковки может быть проектом само по себе, если вы не планируете смешивать с C и какая-то библиотека... bmp выполнимо, просто данные в перевернутом виде, а некоторые старые форматы были еще более дружественными, просто не могу вспомнить ни одного)   -  person Ped7g    schedule 20.08.2017
comment
Я использую режим svga - 101H - 640x480 - 256 упакованных пикселей. Я видел, как некоторые используют растровые изображения, и пытаюсь научиться читать растровые файлы и отображать их.   -  person Jhon Paul Jaspe    schedule 20.08.2017
comment
Хорошо, bmp достаточно просто читать и декодировать, хотя в реальном режиме с сегментами 64k это будет полная PITA для работы в таком высоком разрешении. На самом деле я даже не могу вспомнить, как устроена эта схема памяти в режиме SVGA и что такое банкинг, если каждый 4-й пиксель (не влезает), или каждый бит на 8 плоскостях, или просто весь экран делится на 5+ части. (Я использовал компилятор Watcom C для инициализации всего в защищенном режиме, загрузки файлов, их декодирования и т. д. (все на C/C++) и расширение VBE2.0 для линейного отображения VRAM в защищенном режиме, затем я сделал забавные вещи в 32b asm. , так что все было просто)   -  person Ped7g    schedule 20.08.2017


Ответы (1)


Вам нужно написать/использовать загрузчик изображений или использовать свой собственный формат файла изображения. BMP может показаться простым, но в нем слишком много всего, например форматы пикселей сжатия и т. д., но вы все равно можете сосредоточиться на определенном типе BMP и игнорировать все остальные...

Еще во времена MS-DOS я использовал 256-цветные изображения PCX с палитрой, поскольку я использовал 256-цветные видеорежимы. Вот пример игры NASM LINEZ:

см. подпрограмму pcx:. Он декодирует загруженный файл PCX из памяти ds:0 в необработанное изображение VGA в es:di. Остерегайтесь, он поддерживает только ограничение размера 64 KByte !!! Теперь, чтобы визуализировать изображение, вам нужно будет скопировать es:di содержимое в VideoRAM (при условии, что A000:0000), например, с rep movsd, или вы можете установить для него es:di в первую очередь (но это может мерцать).

Однако этот загрузчик PCX не использует палитру из изображения, поэтому вам нужно ее закодировать... (процедуры для изменения палитры VGA включены в исходный код, который вам просто нужно извлеките значения RGB из PCX, я думаю, это было в конце файла) Посмотрите здесь:

если конвертирует PCX в 32-битный необработанный образ.

Для получения дополнительной информации о программировании игр MS-DOS см. PCGPE 1.0

Вот еще один пример игры (TASM), в котором используется собственный формат файла изображения:

Он имеет текстовые меню, доступ к двоичным файлам, спрайтовую графику 320x200, 3 человека-игрока.

[Edit1] Новый код

Я удалил старый пример кода и вместо этого создал компилируемый и работающий 8-битный PCX со средством просмотра цветовой палитры в TASM. Он использует режим VESA 800x600x256 цветов (103h).

Изображение должно умещаться на экране, а размер файла не должен превышать 64 КБ!!!

Я не добавлял никаких проверок или сообщений об ошибках ... Он просто загружает файл image.pcx и отображает его на VESA, а затем ждет завершения нажатия клавиши. Вот источник TASM:

PCX.ASM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    .386
    IDEAL
    MODEL TINY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    DATASEG
file:   db 'image.pcx',0    ;filename to load
buff:       
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    CODESEG
    STARTUPCODE

    scrxs   equ 800
    scrys   equ 600
    mov ax,103h ; VESA 800x600x256
    call    vesamod
    mov al,0
    call    vesapag

;   scrxs   equ 320
;   scrys   equ 200
;   mov ax,19   ; VGA 320x200x256
;   int 10h

    lea dx,[file]   ; load PCX into DS:buff, CX bytes
    call    fopen
    lea dx,[buff]
    mov cx,64000    ; some max value to fit into DS segment
    call    fread       ; CX is PCX real size
    call    fclose

    lea si,[buff]   ; decode directly to VRAM
    mov ax,0A000h
    mov es,ax
    mov di,0
    call    pcx
mainl0:
    mov ax,256  ; test keyboard
    int 16h
    jz  mainl0
    sub ax,ax   ; clear key buffer
    int 16h

    mov ax,3    ;|VGA 80x25 text
    int 16
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vesamod:pusha               ;set VESA videomode ax
    mov     bx,ax
    mov     ax,4f02h
    int     16
    popa
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vesapag:pusha               ;al=page  switch vesa video page window A
    mov [cs:scrpag],al
    mov     dl,al
    sub     dh,dh
    sub     bx,bx
    mov     ax,4f05h    ; window A
    int     16
    popa
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  .386P
scrpag  db 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  .386P
hand    dw 0        ;###    handler...
ferr    db 0        ;###    DOS error code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fopen:  pusha       ;DS:DX = file name, [hand] <= file handle
    mov ax,3D02h
    int 21h
    mov bl,0
    jnc fopen0
    mov bl,al
    sub ax,ax
fopen0: mov [cs:hand],ax
    mov [cs:ferr],bl
    popa
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fclose: pusha       ;[hand] = file handle
    mov bx,[cs:hand]
    mov ah,3eh
    int 21h
    mov bl,0
    jnc fclose0
    mov bl,al
    sub ax,ax
fclose0:mov [cs:ferr],bl
    mov [cs:hand],ax
    popa
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fread:  pusha       ;DS:DX = adr, CX = lenght, [hand] = hand, CX => read
    mov bx,[cs:hand]
    mov ah,3Fh
    int 21h
    mov bl,0
    jnc fread0
    mov bl,al
    sub ax,ax
fread0: mov [cs:ferr],bl
    mov [cs:freadsz],ax
    popa
    mov cx,[cs:freadsz]
    ret
freadsz dw 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pcx:    pusha           ;decode pcx at ds:si to es:di cx = PCX size
    push    ds
    push    es
    push    ecx
    push    edx

    push    si      ;set palette
    add si,cx
    sub si,768
    sub ax,ax   
pall0:  mov dx,3C8h
    mov al,ah
    out dx,al
    inc dx
    lodsb
    shr al,2
    out dx,al
    lodsb
    shr al,2
    out dx,al
    lodsb
    shr al,2
    out dx,al
    inc ah
    jnz pall0
    pop si

    mov ax,[ds:si+8]    ;get xs
    sub ax,[ds:si+4]
    inc ax
    mov [cs:pcxxs],ax
    mov [cs:pcxx],ax

    mov ax,[ds:si+10]   ;get ys
    sub ax,[ds:si+6]
    inc ax
    mov [cs:pcxys],ax   

    mul [cs:pcxxs]
    push    dx
    push    ax
    pop edx
    add si,128      ;src start after pcx header
    sub ecx,ecx     ;RLE decoder of PCX
pcxl0:  lodsb
    mov cx,1
    cmp al,192
    jb  pcxr0
    mov cl,al
    and cl,63
    lodsb
pcxr0:  mov bx,cx
pcxl1:  call    point

    dec [cs:pcxx]   ;correct next screen line position if end of PCX line
    jnz pcxr1   
    mov ax,[cs:pcxxs]
    mov [cs:pcxx],ax
    neg ax
    add ax,scrxs
    add di,ax
    jnc pcxr1
    ; page swith
    mov al,[cs:scrpag]
    inc al
    call    vesapag

pcxr1:  loop    pcxl1
    mov cx,bx
    sub edx,ecx
    jz  pcxesc
    jnc pcxl0

pcxesc: pop edx
    pop ecx
    pop es
    pop ds
    popa
    ret
pcxxs   dw  0   ;PCX resolution
pcxys   dw  0
pcxx    dw  0   ;actual X coordinate 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
point:  mov [es:di],al      ;point      ;estosb 
    inc di
    jnz pntesc
    ; page swith
    mov al,[cs:scrpag]
    inc al
    call    vesapag
pntesc: ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Итак, возьмите любое изображение до 800x600, преобразуйте его в 256-цветный PCX с палитрой и переименуйте его в image.pcx. Затем поместите его в свой файл *.com и запустите. Я скомпилировал его со скриптом расширения командира Volcov vc.ext следующим образом:

asm:@c:\language\compil\tasm\tasm !.! /ic:\language\source\tasm\inc
    @c:\language\compil\tasm\tlink !.obj /t /x
    @del !.obj

поэтому каждый раз, когда я нажимаю Enter в любом файле asm, он компилируется. Просто измените пути, и если вы не нацелены на файлы *.com, измените переключатель /t соответствующим образом. Вот предварительный просмотр из моего DOSBox:

предварительный просмотр

person Spektre    schedule 20.08.2017
comment
Кстати, как в графическом режиме напечатать строку крупным шрифтом. Я использую сейчас 800x600 256 цветов. - person Jhon Paul Jaspe; 20.08.2017
comment
Написание загрузчика изображений, возможно, пока слишком сложно для меня, я буду рисовать блок за блоком пикселей. Спасибо, что научили меня некоторым идеям - person Jhon Paul Jaspe; 20.08.2017
comment
@JhonPaulJaspe используйте более крупный шрифт или удвойте пиксели. Шрифты можно получить из EGA/VGA ROM или использовать изображение, подобное этому ASCII 8x8 пикселей шрифт 32x8 символов текстура. Для загрузчика достаточно скопировать мою подпрограмму pcx и использовать ее на загруженном в память файле. для более чем 64 КБ вам нужно добавить переключение страниц ... либо с помощью VESA BIOS, либо с помощью LFB .... но это больше подходит для защищенного режима, с которым у меня нет опыта ... - person Spektre; 21.08.2017
comment
Как? я не понимаю, разве в видеосервисах нет функции, которая бы увеличивала размер шрифта? Я пробовал ah = 1122h, 1123h, 1124h, в int 10h, и размер шрифта действительно был больше, но был искажен и не читался. я не знаю - person Jhon Paul Jaspe; 21.08.2017
comment
извините, но я не могу понять некоторые вещи, которые вы упомянули, такие как загрузчик или подпрограмма pcx - person Jhon Paul Jaspe; 21.08.2017
comment
@JhonPaulJaspe 1. в режиме gfx вы должны использовать свои собственные функции печати строк. 2. найдите блок кода в моем ответе для pcx: это декодер pcx для необработанного 256-цветного изображения без палитры. Таким образом, вам нужно просто скопировать его источник в свой проект и вызвать его с установленными регистрами ... ему нужен только файл, загруженный в память, что вы можете сделать, как вы упомянули, вы можете открыть текстовые файлы и в качестве места назначения выбрать некоторую память или использовать VRAM напрямую . Он написан для видеорежима 320x200x256, поэтому начните с него, и при работе вы можете перекодировать до 800x600 или любого другого. - person Spektre; 21.08.2017
comment
похожи ли страницы видео в int 10h на слои в таких программах, как фотошоп? при этом графика на 1 странице независима от другой? Я рисую статическую графику на странице 0, затем я рисую графику на странице 1, которая будет подвижной. Как очистить страницу 1, не затрагивая другие страницы? Я пробовал, выбирая активную страницу 1, затем рисую черным на весь экран, затем снова выбираю активную страницу 0. но графика, нарисованная на странице 0, не возвращается. - person Jhon Paul Jaspe; 22.08.2017
comment
@JhonPaulJaspe Страницы на VESA - это всего лишь части экрана размером 64 КБ, которые нельзя перемещать (если я правильно помню). Они существуют, потому что вы можете адресовать только 64 КБ из VRAM, но для видеорежима требуется больше ... 800x600x256-> 7x64KByte. Если вы находитесь в защищенном режиме, вы можете получить доступ ко всей VRAM, если отобразите ее как LFB в пространство памяти процессора, но это намного выше моих знаний (я использовал только реальный режим). - person Spektre; 22.08.2017
comment
мой метод перемещения графики будет таким: удалить предыдущую графику, увеличить позицию, а затем снова нарисовать. я думаю очистить весь экран на странице видео 1, чтобы удалить предыдущую графику. Пока содержимое на странице видео 0 все еще останется и будет видно, затем снова нарисуйте - person Jhon Paul Jaspe; 22.08.2017
comment
@JhonPaulJaspe, вы смешиваете страницы с обратной / двойной буферизацией, это не одно и то же ... - person Spektre; 22.08.2017
comment
извините, у меня много неправильных представлений, еще один вопрос. В С++ вы можете создавать файлы заголовков и использовать их в другом файле cpp. Есть ли способ реализовать это в сборке? например, у меня есть mainProgram.asm, тогда я хочу создать subProgram.asm, а подпрограмма содержит много процедур и макросов. и я хочу включить их в основную программу, например #include ‹subProgram.asm› или что-то в этом роде. Можно ли сделать это? Потому что мой код становится очень длинным и им трудно управлять - person Jhon Paul Jaspe; 22.08.2017
comment
Я видел, как некоторые используют include filename.inc, что это за файл .inc? это то, что мне нужно, чтобы реализовать то, что я сказал ранее ^? как это сделать? - person Jhon Paul Jaspe; 22.08.2017
comment
@JhonPaulJaspe, вы можете использовать директиву include 'filename' ... используются расширения *.asm, *.inc; *.lib, все они находятся в asm. - person Spektre; 22.08.2017
comment
в моем mainProgram.asm у меня есть .model .data, .stack, .code. в моем subProgram.asm, у меня они тоже есть, я пытался использовать include subProgram.asm, он собран, но когда я вызываю процедуру из subProgram.asm в mainProgram.asm, это не работает. - person Jhon Paul Jaspe; 22.08.2017
comment
БЛЯДЬТ, Я УСПЕШНО ВКЛЮЧИЛ ФАЙЛ ASM, Я УДАЛ ДИРЕКТИВЫ В МОЕЙ ПОДПРОГРАММЕ И ПРОСТО ОСТАВИЛ ТАМ .CODE, И ЭТО РАБОТАЕТ БЛЯДЬ БЛЯДЬ. СПАСИБО, МУЖИК - person Jhon Paul Jaspe; 22.08.2017
comment
@JhonPaulJaspe да, директивы в подфайлах портят ситуацию, поскольку вы получили их и в основном файле, что вызывает конфликт между ними ... include просто копирует файл в то место, где находится include (как в C++), поэтому вам нужно быть будьте осторожны с использованием сегментов DATA и CODE во включаемых файлах... Кстати, я пытался скомпилировать декодер pcx под TASM, но он не работает из-за несовместимости компилятора (он был написан в NASM) Я, должно быть, забыл изменить что-то, чего TASM не делает вроде... ааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааээээээааааааааааааааа, теперь я ненавижу TASM, теперь я вспомнил, почему я перешёл на NASM…. - person Spektre; 22.08.2017
comment
@JhonPaulJaspe добавил, что edit1 наконец нашел проблему с TASM (метки сегментов данных не начинаются со смещения 0, а также заработала прямая адресация памяти) - person Spektre; 22.08.2017