Иллюстрированный самоучитель по SVGA

Иллюстрированный самоучитель по SVGA


 

Точки и их адреса

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

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

Замечание
Размер ячейки видеопамяти (кода точки) зависит от установленного видеорежима и может изменяться от одного до четырех байтов.

Мы сознательно описали упрощенную схему отображения содержимого видеопамяти на экран монитора. Фактически она может быть более сложной. поскольку стандарт VESA позволяет перемещать начало отображаемой области (display start) и изменять логический размер строки. Об этом говорилось в главе 1 при описании функций VBE. На практике упрощенная схема применяется наиболее часто, поэтому примем ее за основу.

При описанном способе отображения адрес точки равен ее порядковому номеру, умноженному на размер кода в байтах (на 1, 2, 3 или 4). В режимах PPG код точки занимает один байт, поэтому ее адрес в видеопамяти совпадает с порядковым номером.
Связь адресов с координатами. Порядковый номер точки (N) вычисляется по значениям координат, задаваемых в виде номеров строки (row) и столбца (column), на пересечении которых она расположена. Номера строк и столбцов начинаются с нуля. Поэтому для вычисления порядкового номера точки надо номер строки умножить на количество точек в строке (Horsize) и к произведению прибавить номер столбца:

N=row * Horsize + column

При работе в видеорежимах PPG полученный результат является абсолютным адресом байта памяти, содержащего код точки. С учетом сегментирования видеопамяти из него надо выделить номер окна и адрес (смещение) в этом окне.

При умножении с помощью команды mul результат автоматически делится на две нужные нам части (вспомните пояснения к примеру 3.3). Номер окна находится в регистре dx, а адрес — в регистре ах. Адрес не требует никакой коррекции, а номер окна надо умножить на единицу приращения значения окна (GrUnit), которая зависит от особенностей видеоконтроллера, способ ее определения описан в главе 2. Если задача работает со страницами видеопамяти, то к результату умножения номера окна на GrUnit прибавляется значение базового окна (значение переменной Base_win).
При работе в графических режимах VGA такие вычисления выполняют две специальные функции прерывания int 10h. Функция ось записывает, а ооь считывает код точки по заданным номерам страницы, строки и столбца. Однако для режимов SVGA эти функции непригодны, поскольку реализованный в них алгоритм рассчитан на расположение точек в пределах одного сегмента видеопамяти. Поэтому вам придется составить и включить в текст задачи собственную подпрограмму для вычисления адресов точек видеопамяти.

Подпрограмма CallWin

В примере 3.4 приведен текст подпрограммы, высляющей адрес точки описанным способом. Вычисленный адрес окна присваивается переменной cur_win, окно устанавливается и оказывается текущим. Смещение (адрес) в этом окне помещается в регистр di. Перед обращением к подпрограмме в регистрах сх и dx указываются, соответственно, номера столбца и строки.

Пример 3.4. Вычисление и установка окна и адреса точки

CallWin: PushReg <dx, ax>
сохранение регистров dx и ах
mov ax, horsize
помещаем в ах размер строки
mul dx
умножаем на номер строки
add ax, ex
прибавляем номер столбца
adc dx, 00
учитываем возможность переполнения
mov di, ax
копируем адрес в регистр di
mov ax, GrUnit
единица приращения окна
mul dl
умножаем на номер окна
add ax, Base win
! ! только при работе со страницами ! !
mov Cur win, ax
копируем окно в Cur win
PopReg <ax, dx>
восстанавливаем регистры
jmp SetWin
установка окна и выход

Прежде чем рассматривать примеры использования этой подпрограммы, несколько слов об особенностях команды умножения (mul). При ее записи явно указывается только один операнд, второй выбирается из аккумулятора (ai, ax или еах), куда его надо предварительно поместить. Команда может умножать байты, простые или двойные слова, размер сомножителей определяется по размеру (типу) указанного в команде операнда. В зависимости от размера сомножителей произведение может содержать Гб, 32 или 64 разряда и соответственно находиться в регистре ах, в регистрах dx и ах, или в регистрах edx и еах. В примере 3.4 первая команда mul dx умножает слова, поэтому произведение расположено в регистрах dx и ах, а вторая (mul di) умножает байты, поэтому результат занимает только регистр ах.

Для того чтобы с адресом точки можно было работать, надо установить вычисленное окно видеопамяти. Поэтому в примере 3.4 номер окна записывается в Cur_win и происходит переход на процедуру setwin, которая устанавливает окно. Смещение в окне помещается в регистр di для того, чтобы его можно было использовать для записи кодов точек с помощью строковой операции stos.

В примере 3.4 нет команды возврата из подпрограммы (ret). Она не нужна потому, что процедура установки окна не вызывается командой call Setwin, а происходит безусловный переход на ее начало (jmp setwin). Возврат на вызывающий модуль выполнит процедура setwin.

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

Важно
При замене команды call командой jmp надо следить за тем, чтобы в верхушке стека находился адрес возврата на вызывающий модуль.

Указание номеров столбца и строки в регистрах сх и ах выбрано для совместимости с драйвером манипулятора "мышь", который описан в главе 6. При каждом перемещении мыши приходится вычислять новый адрес начала рисунка курсора, это и объясняет выбор указанных регистров.

Использование CallWln

В примере 3.5. показано, как можно поместить точку белого цвета в центр экрана. Будем считать, что переменные Horsize и versize содержат количество точек на экране по горизонтали и вертикали, белый цвет имеет код огь, а регистр es содержит код сегмента видеобуфера.

Пример 3.5. Вывод белой точки в центр экрана

mov dx, versize ; количество точек по вертикали
shr dx, 01 ; уменьшаем в 2 раза
mov ex, horsize ; количество точек по горизонтали
shr сх, 01 ; уменьшаем в 2 раза
call CallWin ; устанавливаем окно и адрес
mov al, OFh ; помещаем в al код белого цвета
mov es :[di], al ; рисуем точку
; продолжение программы

Адреса каждой точки вычисляются тем или иным способом при любой работе с графическими объектами — от вывода на экран заранее подготовленного рисунка до построения сложных геометрических фигур. Поэтому эффективность любого алгоритма, предназначенного для работы с графикой, во многом зависит от того, как организована работа с адресами точек.

Наибольшее время занимает вычисление адреса каждой точки по значениям ее координат. Поэтому процедуры типа Caiiwin используются только для нахождения адресов опорных точек, начиная с которых производится построение изображения. Например, такой точкой может быть левый верхний УГОЛ прямоугольной области, в которой должен располагаться рисунок.

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

Смежные точки и их адреса

Смежные точки расположены на экране монитора рядом друг с другом. Если опорная точка не лежит на границе экрана, TO ее окружает 8 смежных точек. Их расположение показано в левой части табл. 3.3, где опорной является точка с номером 0. В правой части таблицы приведены приращения адресов видеопамяти смежных точек относительно адреса опорной точки. Для вычисления адреса смежной точки к опорному адресу прибавляется смещение, указанное в соответствующей ячейке таблицы. Буква ь обозначает переменную Horsize.

Таблица 3.3. Расположение и адреса смежных точек

Расположение точек
Приращения адресов
8
6
7
-1-h
-h
1-h
5
0
1
-1
0
1
4
2
3
h-1
h
h+1

Замечание
Команды, выполняющие строковые операции, обязательно изменяют содержимое индексного регистра, поэтому после их выполнения он содержит адрес не текущей, а следующей точки. Аналогичная ситуация возникает и после выполнения цикла построения строки с использованием обычных команд. Поэтому при составлении программы разберитесь, какой именно адрес вы будете корректировать, — возможно, он уже увеличен на 1.

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