Рисуем пиксел в графическом режиме

Графические режимы могут быть разбиты на шесть групп в зависимости от количества бит, отводимых каждому пикселу:

1 бит/пиксел, 2 цвета, одна битовая плоскость:
CGA mode 6 разрешение 640*200
2 бит/пиксел, 4 цвета, одна битовая плоскость:
CGA mode 4 разрешение 320*200
4 бит/пиксел, 16 цветов, четыре битовых плоскости:
EGA mode 0Dh разрешение 320*200
EGA mode 0Eh разрешение 640*200
EGA mode 10h разрешение 640*350
VGA mode 12h разрешение 640*480
VESA mode 102h разрешение 800*600
VESA mode 104h разрешение 1024*768
VESA mode 106h разрешение 1280*1024
8 бит/пиксел, 256 цветов, одна битовая плоскость:
VGA mode 13h разрешение 320*200
VESA mode 100h разрешение 640*400
VESA mode 101h разрешение 640*480
VESA mode 103h разрешение 800*600
VESA mode 105h разрешение 1024*768
16 бит/пиксел, 65536 цветов, одна битовая плоскость(существуют также 32768-цветные режимы):
VESA mode 111h разрешение 640*480
VESA mode 114h разрешение 800*600
24 бит/пиксел, 16777216 цветов, одна битовая плоскость:
VESA mode 112h разрешение 640*480
Исключая 4-битные режимы пикселы в памяти располагаются на одной плоскости (plane), т.е., если координаты пиксела (x,y), то адрес, по которому располагается этот пиксел в памяти может быть вычислен как
Address = LineLength*y + Bits*x/8
где LineLength — количество байтов, занимаемых каждой строкой пикселов, а Bits — количество бит, занимаемым пикселом.

Исключениями являются режимы CGA номер 4 и 6, у которых четные и нечетные линии расположены в различных сегментах памяти.

В шестнадцатицветных режимах экранная память разделяется на 4 битовые плоскости. Каждый бит значения цвета пиксела расположен на своей плоскости. Адрес байта, хранящего пиксел с координатами x,y можно вычислить как
Address = LineLength*y + x/8
где LineLength — число байтов, занимаемых одной строкой.

Рисование пиксела с координатами x,y в 16-цветных режимах подразумевает установку бита во всех четырех плоскостях. Активная в данный момент плоскость выбирается записью в соответствующие порты видеокарты.

Режимы CGA, EGA и VGA поддерживаются всеми стандартными BIOS. Переключение в эти режимы обычно осуществляется простым вызовом функций BIOS.

Pixel$
Во всех режимах VGA следующая процедура Pixel$ может нарисовать пиксел. Нужно отметить, что процедура достаточно медленная, т.к. используются вызовы функций BIOS.

Pixel$ proc
;Рисует пиксел во всех режимах VGA.
;Входные данные: x в AX, y в BX, цвет в CX
;Выходные данные: регистры не сохраняются
mov DX,BX ;строка y
xchg AX,CX ;CX — колонка x, AL — цвет
sub BH,BH ;0 страница
mov AH,0Ch ;выводим пиксел
int 10h
ret
Pixel$ endp
Самый интересный режим VGA — это режим 13h с возможностью отображения 256 цветов и разрешением 320*200. Номер цвета 0…255 соответствуют значениям в палитре, где все цвета представлены в виде определенных сочетаний красной, зеленой и синей компонент. Следующая процедура VGApxl$ рисует пиксел в этом режиме. Она работает достаточно быстро, однако существуют еще более быстрые варианты.

;данные:
VGA_seg dw 0A000h ;сегмент памяти экрана VGA

VGApxl$ proc
;Рисует пиксел в режиме VGA 13h.
;Входные данные: x в AX, y в BX, цвет в CX
;Выходные данные: регистры AX и BX не сохраняются
xchg BH,BL ;умножаем y на 256, BL=0
add AX,BX ;AX = x+256y
shr BX,1 ;делим 256y на два
shr BX,1 ;BX = 256y/4 = 64y
add BX,AX ;BX = x+320y
mov AX,ES ;сохраняем значение ES
mov ES,VGA_seg ;сегмент памяти экрана VGA
mov ES:[BX],CL ;выводим байт на экран
mov ES,AX ;восстанавливаем значение регистра ES
ret
VGApxl$ endp

Функция синуса в 32-битной системе с фиксированной точкой
Процедура Rsin$ вычисляет тригонометрическую функцию sin от 32-битного аргумента. 32-битная система с фиксированной точкой определяется следующим образом:

;значение переменной F32bit = 4.750
F32bit dw 49152 ;дробная часть (0.75*65536)
dw 4 ;целая часть
Использование процедуры:
Входные данные: смещение аргумента в BX, смещение результата в AX. Аргумент задает угол в градусах.
Выходные данные: значение функции sin, записываемое в переменную, смещение которой определяется регистром AX. Значения регистров не сохраняются.

Например, sin(30.5°) вычисляется так:

Angle dd 001E8000h ;старший байт=30, младший байт=32768
Result dd ? ;сюда будет записан результат
….
mov AX,offset Result
mov BX,offset Angle
call Rsin$
В результате такого вызова вы получите результат 0.50752 в то время как правильное значени еравно 0.50754

Rsin$ proc
; значение синуса аргумента (двойное слово по смещению BX) вычисленное как двойное слово по смещению AX.
; Угол (по смещению BX) в градусах в диапазоне -360…360.
push AX ;сохраняем смещение результата
mov AX,[BX+2] ;целая часть угла
mov CX,[BX] ;дробная часть угла
mov DX,1 ;знак результата — +1 или -1
or AX,AX ;какой знак?
jns Rsin_1
not AX ;меняем знак
not CX
add CX,1
adc AX,0
neg DX ;также меняется знак результата
Rsin_1: ;теперь имеем угол в диапазоне 0…360
; уменьшаем диапазон до 0…180
cmp AX,180 ;угол больше 180?
jl Rsin_2
sub AX,180
neg DX ;изменяем знак результата
Rsin_2: ;теперь угол AX:CX в диапазоне 0…179.99998
cmp AX,90 ;угол больше 90?
jl Rsin_3
mov BX,180 ;вычисляем 180-угол
sub SI,SI
sub SI,CX
sbb BX,AX
mov AX,BX
mov CX,SI
Rsin_3: ;угол в AX:CX в диапазоне 0…90
push DX ;сохраняем знак результата в стеке
cmp AX,90 ;угол равен 90?
jne R_sin4
mov AX,1 ;возвращаем 1.0000
sub BX,BX
jmp short Rsin_9
R_sin4:
mov SI,offset Rsin_t ;таблица значений синусов
add SI,AX
add SI,AX
sub AX,AX ;целая часть значения синуса
mov BX,[SI] ;дробная часть
or CX,CX ;дробная чать равна 0?
jz Rsin_9
; интерполяция между значениями [SI] и [SI+2]
mov AX,[SI+2]
sub AX,BX ;AX = sin(a+1)-sin(a)
mul CX ;CX=0… 0.9999, результат DX= AX*CX/65536
add BX,DX ;добавим получившийся результат к значению из таблицы
sub AX,AX ;целая часть результата
Rsin_9:
pop DX ;корректируем знак результата AX:BX
or DX,DX
jns Rsin_loppu
not AX ;изменяем знак результата
not BX
add BX,1
adc AX,0
Rsin_loppu:
pop DI ;смещение результата
mov [DI+2],AX ;записываем целую часть
mov [DI],BX ;дробная часть
ret
Rsin$ endp
;таблица синусов
Rsin_t dw 0,1144,2287, 3430, 4572, 5712, 6850, 7987, 9121,10252
dw 11380,12505,13626,14742,15855,16962,18064,19161,20252,21336
dw 22415,23486,24550,25607,26656,27697,28729,29753,30767,31772
dw 32768,33754,34729,35693,36647,37590,38521,39441,40348,41243
dw 42126,42995,43852,44695,45525,46341,47143,47930,48703,49461
dw 50203,50931,51643,52339,53020,53684,54332,54963,55578,56175
dw 56756,57319,57865,58393,58903,59396,59870,60326,60764,61183
dw 61584,61965,62328,62672,62997,63303,63589,63856,64104,64332
dw 64540,64729,64898,65048,65177,65287,65376,65446,65496,65526
dw 0 ;для интерполяции

Рисуем пиксел в графическом режиме: 1 комментарий

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *