Консультация № 179638
30.07.2010, 16:16
0.00 руб.
0 3 0
Уважаемые эксперты! Как можно переделать нижеприведённую программу с 13h vga-режима в 105h svga-графический, т.е. 1024х768х256. Не могу понять, как переключаются окна видеопамяти. Если считать, что данный режим поддерживается и делать проверку на это не нужно, то сначала функцией 4F02h нужно установить режим 105h. Потом для переключения окон можно или сразу установить функцию 4F05h, или с помощью 4F01h получить информацию о режиме, с тем расчётом, что по смещению +0Ch адреса буфера расположены 4 байта — адрес процедуры перемещения окна (аналог подфункции 05h, но, как утверждается, выполняется быстрее). У меня получается 1024х768х1/1000h = 12 окон. То ли окно с изображением будет перемещаться, то ли изображение внутри окна. А если несколько изображений, и они находятся в разных окнах и перемещаются?
В BL функции 4F05h заносится номер окна: 0 – окно А, 1 – окно В. Как узнать, какое А, какое В, в чём у них различие? В DX заносится номер окна в видеопамять в единицах дробности. Как понять в единицах дробности?



Приложение:
.model tiny
.386
.code
.startup

mov ax,0013h ;320x200x256
int 10h
;читаем старый обработчик
mov ax,3509h
int 21h
mov old09o,bx
mov old09s,es
;ставим новый обработчик
mov ax,2509h
mov dx,offset new09
int 21h
;настраиваемся на видео буфер
mov ax,0A000h
mov es, ax
cld
keyESC equ 01h
keyUp equ 48h
keyDown equ 50h
keyLeft equ 4Bh
keyRight equ 4Dh
MainLoop:
;считаем адрес
call CalcAdr
;рисуем рисунок
call DrawMovingImage
;задержка
mov cx,5000
MM1: push cx
mov cx,5000
MM2: loop MM2
pop cx
loop MM1
;изменяем координаты
xor dx,dx
xor bx,bx
;изменяем приращение
add bl,DataKey[keyDown]
add dl,DataKey[keyRight]
sub bl,DataKey[keyUp]
sub dl,DataKey[keyLeft]
;контроль
;вертикальная координата
mov ax,bx
cbw
add ax,ImageS
jz IgnoreV
js IgnoreV
push ax
add ax,ImageH
cmp ax,StringHeigth
pop ax
jae IgnoreV
mov imageS,ax
IgnoreV:
;контроль
;горизонтальная координата
mov ax,dx
cbw
add ax,ImageC
jz IgnoreH
js IgnoreH
push ax
add ax,ImageL
cmp ax,StringLength
pop ax
jae IgnoreH
mov imageC,ax
;прячем рисунок
IgnoreH: call ClearImage
;проверяем ESC
cmp byte ptr DataKey[keyESC],1
jnz MainLoop
;востанавливаем старый обработчик
mov ax,2509h
mov dx,old09o
mov ds,old09s
int 21h
;завершение программы
mov ax, 4c00h
int 21h
;старый обработчик
old09o dw ?
old09s dw ?
;наш обработчик
new09: pusha
;читаем порт
in al,60h
;заполняем массив
xor bx,bx
mov bl,al
mov al,1
mov cs:DataKey[bx],al
xor bl,80h
xor al,al
mov cs:DataKey[bx],al
;стандартное завершение прерывания
in al,61h
push ax
or al,80h
out 61h,al
pop ax
out 61h,al
mov al,20h
out 20h,al
popa
iret
;
DrawMovingImage proc
pusha
; Записать адрес маски в индексный регистр
mov SI,offset Flm;указатель на маску объекта
; Вывести изображение
mov cx,ImageH ;высота маски
M0: ;Вывести очередную строку маски
push cx
mov CX,ImageL;ширина маски
push di
rep movsb
pop di
;Перейти на следующую строку
add DI,StringLength
pop cx
loop M0
popa
ret
DrawMovingImage endp
ClearImage proc
pusha
; Вывести изображение
mov cx,ImageH ;высота маски
M3: ;Вывести очередную строку маски
push cx
mov CX,ImageL ;ширина маски
mov al, 0
push di
rep stosb
pop di
; Перейти на следующую строку
add DI,StringLength
pop cx
loop M3
popa
ret
ClearImage endp
CalcAdr proc
; Вычислить адрес начальной точки для вывода маски
; Умножить длину строки на номер строки
mov AX,StringLength
mul ImageS
; Прибавить длину колонки
add AX,ImageC
mov DI,AX
ret
CalcAdr endp
.data
DataKey db 256 dup(0)
; Маска
Flm DB 15,15,15,15 ,15,15,15,15 ,15,15,15,15 ,15,15,15,15
ImageL equ $ - Flm; 16 ;ширина маски
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15

DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15

DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15

DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,12,12,12 ,12,12,12,12 ,12,12,12,12 ,12,12,12,15
DB 15,15,15,15 ,15,15,15,15 ,15,15,15,15 ,15,15,15,15
ImageH equ ($ - Flm) / ImageL;16 ;высота маски

StringLength dw 320 ;длина строки
StringHeigth dw 200 ;количество строк
; Позиция маски изображения на экране
ImageS dw 90 ;строка
ImageC dw 150 ;колонка
; Размеры маски изображения
END

Обсуждение

Неизвестный
30.07.2010, 17:14
общий
Adsorores:
Окно это кусок видеопамяти, к которому возможен прямой доступ через буфер по адресу 0x0a0000. Так как буфер имеет размер всего 0x10000, а объем используемой в svga режимах видеопамяти значительно выше ( в вашем случае в 12 раз), то приходится как-то изворачиваться чтобы адресовать всю видеопамять.
Работает это примерно так (для режима 1024x768x8bpp, код не претендует на абсолютную верность и компилируемость, написан по памяти)
Код:
setpixel:
;ax - x, bx - y, cx - color
push ax
mov ax,bx
mov bx,1024 ;width
sub dx,dx
mul bx
pop bx
add ax,bx
adc dx,0
;ax:dx - linear video memory address
;ax - offset, dx - window

push ax
push cx

; set window
mov ax,4f05h
sub bx,bx
int 10h
;set pixel
pop cx
pop si
mov dx,0a000h
mov es,dx
mov byte ptr es:[si],cl
ret


То есть считаем смещение пикселя в видеопамяти по формуле
linear_offset=(x+y*width)*(bpp/8)
страница получается по формуле
page=linear_offset/0x10000
смещение в буфере
buffer_offset=linear_offset%0x10000
дальше вызвать int 10h/4f02h c bx=0 (окно А, выбрать) и dx=page
и записать значение пикселя в буфер со смещением inear_offset
Неизвестный
31.07.2010, 07:22
общий
vladisslav:
Не очень понятно, зачем adc dx,0, если перед этим было sub dx,dx. Ноль складывать с нулём.
«int 10h/4f02h c bx=0 (окно А, выбрать) и dx=page» - в bx в int 10h/4f02h находится номер видеорежима.
Неизвестный
01.08.2010, 01:17
общий
Adsorores:
Цитата: 289969
Не очень понятно, зачем adc dx,0, если перед этим было sub dx,dx.

Результат перемножения ax*bx (32-х разрядный) помещается после mul bx в регистры ax:dx.
Цитата: 289969
int 10h/4f02h c bx=0

Опечатка. В коде правильно.
Должно быть "int 10h/4f05h c bx=0 (окно А, выбрать) и dx=page" конечно же.
Форма ответа