Главная » Ассемблер, Железо » Вывод текста и статических изображений в графических режимах

0

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

Наиболее простым способом вывода на экран текста и статических изображений является метод масок. Вообще говоря, для создания изображения объекта необходимо два массива: массив, содержащий рисунок объекта, и массив, содержащий маску прозрачности, то есть указание, какие точки рисунка должны отображаться на экране, а в каких надлежит сохранить фон изображения. Однако с целью экономии памяти оба массива объединяют и именуют полученный результат маской объекта (рис. 4.11). Таким образом, маска представляет собой растровое изображение объекта, совмещенное с шаблоном прозрачности.

Рис. 4.11. Маска объекта «самолет»

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

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

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

и колонки — читабельность текста в результате несколько улучшается, но снижается емкость экрана в знакоместах (рис. 4.12). Однако обычно символы выводятся вплотную друг к другу, без дополнительных промежутков.

Рис. 4.12. Разметка экрана на знакоместа при выводе текста в графическом режиме (LM — ширина маски символа, Нм — высота маски)

Если необходимо отображать одинаковые по форме объекты различного цвета, например, выводить текстовые символы различными цветами, то маска применяется для кодирования не цвета, а яркости точек изображения. В этом случае процессор не копирует маску прямо в видеопамять, а выполняет вначале сложение базового кода цвета со значением яркости (в 256-цветных режимах) или распределение кода яркости по заданным цветовым компонентам RGB (в режимах DirectDraw).

Рассмотрим теперь примеры выполнения простых операций в различных графических режимах. В листинге 4.2 собраны универсальные

процедуры, предназначенные для установки графических VESA"

режимов, вывода текстовой и числовой информации в видеопамять.

•     Процедура GrabRusFont считывает текущий шрифт 8×16 прямо из памяти видеоконтроллера (по методике, предложенной в [29]) и записывает его в массив Font8xl6. Перед запуском подпрограммы должен быть установлен текстовый режим, а сразу после ее выполнения желательно выполнить переустановку видеорежима.

•     Процедура SetVESAVideoMode проверяет наличие режима VESA с номером, заданным константой GraphicsMode, запоминает в глобальной переменной LinearVndeoBuffer начальный абсолютный (линейный) адрес памяти видеоконтроллера, устанавливает видеорежим, а затем увеличивает логическую длину строки экрана до 1024 пикселов. В случае если режим не поддерживается, процедура завершается немедленным (аварийным) выходом из программы.

•     Процедура SetTrueColor32 осуществляет поиск видеорежима ТгиеСо1ог32 с разрешением, заданным константами ScreenLength и ScreenHei gth, устанавливает его (если он поддерживается видеоконтроллером) и задает логическую длину строки экрана 1024 пиксела. В случае если подходящий режим не обнаружен, процедура завершается немедленным выходом из программы.

•     Процедура WaitVSync предназначена для синхронизации вывода динамических изображений — она выполняет операцию ожидания начала обратного хода луча по кадру.

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

•     Процедура GShowByteHexCode отображает в заданную позицию экрана содержимое регистра AL (байт данных) в шестнадцатерич- ном коде.

•     Процедура GShowHexWord отображает в заданную позицию экрана содержимое регистра АХ (слово данных) в шестнадцатерич– ном коде.

•     Процедура GShowHexDWord отображает в заданную позицию экрана содержимое регистра ЕАХ (двойное слово) в шестнадцатерич- ном коде.

•     Процедура GShowByteBi nCode отображает в заданную позицию экрана содержимое регистра AL (байт данных) в двоичном коде.

•     Процедура GShowBinDWord отображает в заданную позицию экрана содержимое регистра ЕАХ (двойное слово) в двоичном коде.

•     Процедура ShowCol orStri ng выводит текстовую строку заданного цвета в заданную область экрана.

Листинг 4.2. Процедуры общего назначения, предназначенные для установки графических режимов и работы в них

DATASEG

; Место для хранения информации VESA BIOS VESABIOS

DB 512 DUP(?)

; Область для приема информации о параметрах видеорежима

VESAJnfo

DB 256 DUP(?)

; Физический адрес линейного видеобуфера

LinearVideoBuffer DD ?

; Буфер для сохранения шрифта (16×256 байт)

Font8xl6

DB 4096 DUP С ?)

; Позиция отображаемого символа

FontString DW ? ;номер строки шрифта

FontColumn DW ? :номер колонки шрифта

ErrMod

DB 12,17,"Заданный режим не "

DB "поддерживаются контроллером",0 ErrPrm

DB 12,17

DB "Некорректный параметр у функции GShowString’.O

ENDS CODESEG

;* СЧИТЫВАНИЕ "РУССКОГО" ШРИФТА ИЗ ПАМЯТИ * ;*ВИДЕОКОНТРОЛЛЕРА*

;*(процедура параметров не имеет)*

;* Операция захвата шрифта требует перепрограммиро- * ;* вания регистров видеоконтроллера и ее следует * ;* выполнять непосредственно перед переходом из * ;* текстового режима в графический, чтобы не восста- * ;* навливать регистры (при сиене режима они все * ;* равно будут перезаписаны).*

PROC GrabRusFont near pushad

; Перепрограммировать синхронизатор cli

mov DX,3C4h

: Установить последовательную адресацию

; ячеек видеопамяти

mov AX,0704h out DX.AX sti

; Перепрограммировать графический контроллер

Листинг 4.2(продолжение)

mov DX.3CEh

; Выбрать для считывания плоскость 2

mov AX,0204h out DX.AX

; Запретить четную-нечетную адресацию

mov AX.0005h out DX.AX

; Установить окно доступа по адресу AOOOOh

mov AX,0006h out DX.AX

; Скопировать шрифт в буфер FontBxl6

mov АХ,OAOOOh

mov ES.AX

mov SI.O

mov BX,offset FontBxl6

mov DX.256

mov CX.16

mov AL, [ES-.SI]

mov [BX],AL

inc BX

inc SI

loop ЙЁМ

add SI,16

dec DX

jnz Ш0

popad

ret

ENDP GrabRusFont

;* УСТАНОВИТЬ ВИДЕОРЕЖИМ ЧЕРЕЗ ФУНКЦИЮ VESA * ;* (процедура параметров не имеет) *

PROC SetVESAVideoMode near pushad push ES

mov AX,OS

mov ES.AX

; Получить информацию о наличии VESA BIOS

mov AX,4F00h

mov DI,offset VESA_BI0S int lOh

; Получить результат выполнения функции cmp AX,4Fh

jne

@@Err ;функция не выполнена cmp [dword ptr VESA_BI0S],’ASEV’ jne

@@Err ;нет сигнатуры "VESA" cmp [word ptr VESA BIOS+4], 200h

jb

@@Err ;версия "VESA" слишком старая

; Получить параметры видеорежима, номер

; которого задан переменной GraphicsMode

mov AX,4F01h

mov СХ,GraphicsMode

mov DI.offset VESAinfo int lOh

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

mov ЕАХ.[offset VESA_info+28h]

mov [LinearVideoBuffer],EAX

; Установить заданный видеорежим

mov ВХ,GraphicsMode

mov AX.4F02h int lOh

: Устанавливаем заданную логическую ширину строки xor ВХ.ВХ

mov CX.LogicalStringLength

mov AX,4F06h

int lOh

pop ES

popad

ret

: Аварийный выход – нет поддержки VESA

@@Err: MFatalError ErrMod ENDP SetVESAVideoMode

;* УСТАНОВИТЬ ВИДЕОРЕЖИМ TRUECOLOR32 * ;* (процедура параметров не имеет) *

PROC SetTrueCo1or32 near pushad push ES

; Получить информацию о наличии VESA BIOS

mov AX.DS

mov ES.AX

mov AX,4F00h

mov DI. off set VESABIOS int lOh

; Проверить результат выполнения функции cmp AX,4Fh

jne

@@Err :функция не выполнена cmp [dword ptr VESA_BIOS].’ASEV’ jne

@@Err ;нет сигнатуры "VESA" cmp [word ptr VESA_BI0S+4],200h jb P@?rr ;версия "VESA" слишком старая : Найти видеорежим с параметрами TrueCo1or32 640×480 : Загрузить адрес массива номеров

mov ВХ,[word ptr VESA_BIOS+OEh]

mov AX,[word ptr VESA_BIOS+10h]

Листинг 4.2 (продолжение)

mov ES.AX

@@NextMode:

; Получить параметры очередного видеорежина

mov CX,[ES:BX] загрузить ноиер режина cmp СХ,0 :ошибка?

je

@@Err

cmp CX,OFFFFh ;конец списка?

je

@@Егт push ES

mov AX.DS

mov ES.AX

mov AX,4F01h

mov DI,offset VESA info int lOh pop ES

; Проверить значения полей

; Горизонтальное разрешение cmp [word ptr VESA_info+12h],ScreenLength jne

@@NotTrueCo1or32

; Вертикальное разрешение cmp [word ptr VESA_info+14h],ScreenHeigth jne

@@NotTrueCo1or32

; Число битов на пиксел’

cmp [byte ptr VESA_info+19h].32 jne

@@NotTrueCo1or32

; Линейный адрес буфера кадра cmp [dword ptr VESA_info+28h],0 jne

@@SetMode

@@NotTrueColor32:

inc BX jmp

@@NextMode

@@SetMode:

; Выделить адрес линейной области видеопаняти

mov ЕАХ.[offset VESAJnfo+28h]

mov [LinearVndeoBuffer],EAX

; Установить найденный режин

mov AX,4F02h

; Загрузить нонер режима

mov BX.[ES:BX]

; Использовать линейную адресацию or BX,4000h int lOh

; Установить логическую ширину строки

mov AX,4F06h xor BX.BX

mov CX.LogicalStringLength int lOh pop ES

popad ret

; Аварийный выход – нет поддержки заданного режима

@@Err: MFatalError ErrMod ENDP SetTrueColor32

;* ОЖИДАНИЕ ОБРАТНОГО ХОДА ЛУЧА ПО КАДРУ *

PROC WaitVSync NEAR push AX push DX

mov DX,03DAh ;регистр статуса VGA

@@Wai tNotVSyncLoop: in AL.DX

and AL,08h ;выделяем бит вертикальной синхронизации jnz

@@WaitNotVSyncLoop

@@WaitVSyncLoop:

in AL,DX

and AL.OBh ;выделяем бит вертикальной синхронизации

jz

@@WaitVSyncLoop

pop DX

pop AX

ret

ENDP WaitVSync

;*ВЫВОД ТЕКСТОВОЙ СТРОКИ НА ЭКРАН*

;* Все параметры передаются через одну структуру: * ;* первый байт – номер начальной строки (0-47); * ;* второй байт – номер начальной колонки (0-127); * ;* далее идет строка, ограниченная нулем.*

;* Адрес структуры передается через регистры DS:SI. *

PROC GShowString near push AX push DX eld

; Вычисляем адрес для строки в видеопамяти загрузить номер строки экрана в DH lodsb

cmp AL,47

ja

@@Err ;выход за нижнюю границу экрана

mov DH.AL

•.загрузить номер строки экрана в DL lodsb

cmp AL.127

ja

@@Err ;выход за правую границу экрана

mov DL.AL

@@L1:

; Загрузить очередной символ строки в AL

Листинг 4.2 (продолжение) lodsb

; Проверка на 0 (на конец строки) and AL.AL jz P0L2

: Вывести синвол на экран cal1 PutGraChar

jmp

@@L1

; Нормальное завершение

@@L2: pop DX pop AX ret

: Немедленный выход в DOS при ошибке

@@Err: MFatalError ErrPrm ENDP GShowString

;*ВЫВОД ТЕКСТА НА ЭКРАН*

;* GShowText использует процедуру GShowString для * ;* вывода на экран группы строк.*

;* Параметры:*

;* СХ – количество строк:*

;* DS:SI – адрес первой строки в группе.*

;* Строки должны иметь заданный для GShowString фориат * ;* и располагаться в памяти последовательно.*

;* При выводе текста используются принятые по*

;* умолчанию цвет и фон.*

PROC GShowText near

; Цикл вывода строк

@@NextString:

call GShowString loop

@@NextString

; Процедура не сохраняет значения в СХ и SI ret

ENDP GShowText

;* ВЫВОД БАЙТА НА ЭКРАН В ШЕСТНАДЦАТЕРИЧНОМ КОДЕ * ;* Подлрограмма выводит содержииое регистра AL*

;* в шестнадцатеричном коде в указанную позицию*

;* экрана.*

;* Координаты позиции передаются через глобальные * ;* переменные ScreenString и ScreenColumn. После * ;* выполнения операции вывода байта происходит*

;* автоматическое приращение значений этих переменных. *

PROC GShowHexByte near pusha

mov DH,[byte ptr ScreenString]

mov DL,[byte ptr ScreenColumn]

; Вывести старший разряд числа push АХ

; Выделить старший разряд shr AL.4

; Преобразовать старший разряд в код ASCII

add AL,’О’ cmp AL,’9′ jbe mo

add AL.’A’-‘Г- 1 : Вывести разряд числа на экран

@@М0: call PutGraChar

pop АХ

; Вывести нладтий разряд числа

; Выделить нладтий разряд числа and AL.0FH

; Преобразовать нладтий разряд в код ASCII

add AL.’О’ cmp AL,’9′ jbe

@@M1

add AL.’A’-‘g’- 1

; Вывести разряд числа на экран

@@М1: call PutGraChar

: Подготовка для вывода следующих байтов

; Перевести текущую позицию на 2 символа влево

add [ScreenColumn],2

; Проверить пересечение правой границы экрана cmp [ScreenColumn],80 jb

@@End

; Если достигнута правая граница экрана – перейти : на следующую строку sub [ScreenColumn],80

inc [ScreenString] : Конец подпрограммы

@@End: рора ret

ENDP GShowHexByte

;*ВЫВОД 16-РАЗРЯДНОГО СЛОВА НА ЭКРАН*

;*В ШЕСТНАДЦАТИРИЧНОМ КОДЕ*

;* Параметры:*

;* АХ – число, которое будет выведено на экран. * ;* Номер строки передается через глобальную*

;* переменную ScreenString, номер столбца – через * ;* переменную ScreenColumn, цвет текста определяется * ;* переменными DefaultColor и DefaultBackground. *

PROC GShowHexWord NEAR

Листинг 4.2(продолжение)

xchg AL.AH

cal1 GShowHexByte

xchg AL.AH

call GShowHexByte

ret

ENDP GShowHexWord

;*ВЫВОД 32-РАЗРЯДНОГО СЛОВА НА ЭКРАН*

;*В ШЕСТНАДЦАТЕРИЧНОМ КОДЕ*

;* Параметры:*

;* ЕАХ – число, которое будет выведено на экран. * ;* Нонер строки передается через глобальную*

;* переменную ScreenString, номер столбца – через * ;* переменную ScreenColumn, цвет текста определяется * ;* переменными Defaulted or и DefaultBackground. *

PROC GShowHexDWord NEAR rol EAX.8 call GShowHexByte rol EAX.8 cal1 GShowHexByte rol EAX.8 call GShowHexByte rol EAX.8 call GShowHexByte ret

ENDP GShowHexDWord

;*ВЫВОД БАЙТА НА ЭКРАН В ДВОИЧНОМ КОДЕ*

;* Подпрограмма выводит содержимое регистра AL*

;* в двоичном коде в указанную позицию экрана.*

;* Координаты позиции передаются через глобальные * ;* переменные ScreenString и ScreenColumn. После * ;* выполнения операции вывода байта происходит*

;* автоматическое приращение значений этих переменных. *

PROC GShowBinByte near pusha

mov DH.[byte ptr ScreenString]

mov DL,[byte ptr ScreenColumn] : Копируем отображаемый байт в BL

mov BL.AL : Отобразить разряды числа (начиная со старшего)

mov СХ,8 :счетчик разрядов 0Й.О:

mov AL, ‘О’

: Выделить очередной разряд числа rol BL.1

jnc

@@L1

mov AL.’l’

; Вывести разряд числа на экран РИЛ: call PutGraChar

1oop

@@L0

; Подготовка для вывода следующих байтов

; Перевести текущую позицию на В символов влево

add [ScreenColumn],В

; Проверить пересечение правой границы экрана cmp [ScreenColumn],80 jb

@@End

; Если достигнута правая граница экрана -

; перейти на следующую строку sub [ScreenColumn],ВО

inc [ScreenString]

; Конец подпрограммы

@@End: popa ret

ENDP GShowBinByte

;* ВЫВОД 32-РАЗРЯДНОГО СЛОВА НА ЭКРАН В ДВОИЧНОМ КОДЕ * ;* Параметры:*

;* ЕАХ • число, которое будет выведено на экран. * ;* Номер строки передается через глобальную*

;* переменную ScreenString, номер столбца – через * ;* переменную ScreenColumn, цвет текста определяется * ;* переменными DefaultColor и DefaultBackground.*

PROC GShowBinDWord NEAR rol ЕАХ,В call GShowBinByte

inc [ScreenColumn] rol EAX.B call GShowBinByte

inc [ScreenColumn] rol EAX,8 call GShowBinByte

inc [ScreenColumn] rol EAX,8 call GShowBinByte ret

ENDP GShowBinDWord ENDS

Универсальная процедура вывода текстовой строки опирается на процедуру вывода символа, специфическую для каждого типа видео- режима. В листинге 4.3 показан вариант реализации процедуры вывода символа PutGraChar и процедуры очистки экрана GClearScreen для 256-цветных режимов с линейным видеобуфером.

ВНИМАНИЕ

Стандартные растровые шрифты MS-DOS с размером маски символа 8×16 целесообразно использовать только при низком разрешении экрана (до 800×600 включительно). При разрешении 1024×768 и выше программист вынужден создавать (при помощи типовой или самодельной программы — генератора шрифтов) свой собственный шрифт, увеличенный в 1,5-2 раза (12×24 или 16×32).

Листинг 4.3. Процедуры вывода символа и очистки экрана для 256-цветных режимов с линейной адресацией видеобуфера

0ATASEG

: Цвет текста в графическом режиме по умолчанию DefaultColor

DB WHITE :белый : Цвет фона в графическом режиме по умолчанию DefaultBackground

DB BLACK :черный ENDS

C0DESEG

‘;* ВЫВОД СИМВОЛА 8×16 НА ЭКРАН В ГРАФИЧЕСКОМ РЕЖИМЕ *

;*(для 256-цветных режимов)*

;* Все параметры передаются через регистры:*

;* AL – ASCII-код символа:*

;* DH – номер текстовой строки экрана;*

;* DL – номер текстовой колонки экрана;*

;* Используются цвет символов и цвет фона,*

;* заданные по умолчанию.*

PROC PutGraCharNEAR

pushDS pushad

movCX,[CS:Ma i nDataSeg]

movDS.CX

eld

: Смещение символа от начала шрифта

movSI,offset Font8xl6

xorAH.AH

shlAX.4

addSI.AX

; Вычислить левый верхний угол символа

xorEBX.EBX

movBL.DH

shlEBX. 14 .-умножить номер строки на 16*1024

xorDH.DH

shlDX,3 ;умножить номер столбца на 8

orBX.DX

movEDI,EBX

addEDI,[Li nearVideoBuffer]

mov BL,[DefaultColor]

mov DL,[DefaultBackground]

mov AH,16 :счетчик строк иаски буквы

@@М0: lodsb

mov СХ.8 ;счетчик точек в строке иаски

@@М1: rol AL.1 jc

@@И2

mov [GS:EDI].DL

jmp <а@МЗ

@@И2:

mov [GS:EDI].BL

@@ИЗ:

inc EDI loop

@@M1

add EDI.LogicalStringLength-8 dec AH jnz

@@M0 : Завершение процедуры

@@EndPutGraChar: popad pop DS

inc DL ret

ENDP PutGraChar

;* ОЧИСТКА ЭКРАНА В ГРАФИЧЕСКОМ РЕЖИМЕ * ;* (процедура параметров не имеет) *

PROC GClearScreen NEAR pushad

; Умножить высоту экрана ScreenHeigth на логическую

; ширину строки 1024 пиксела

mov ЕСХ,ScreenHeigth shl ЕСХ,10 : Загрузить в индексный регистр линейный

; адрес видеопамяти

mov EDI.[Li nearVi deoBuffer]

; Заполнить видеопамять нулями

mov AL,0 ;черный цвет

@@NextPixels:

mov [GS:EDI] ,AL

inc EDI

dec ECX

jnz

@@NextPixels

popad

ret

ENDP GClearScreen ENDS

Программа Test256Mode, приведенная в листинге 4.4, демонстрирует вывод текста и графики (пучка прямых линий) в 256-цветном

режиме. В нем используются процедуры из листингов 4.2 и 4.3, а также универсальные модули из глав «Работа с клавиатурой» и «Недокументированные возможности процессоров Intel 80x86». При рисовании линий применяются упрощенные алгоритмы, каждый из которых позволяет чертить линию только под строго определенным углом.

В приведенном примере выбрано разрешение 640×480 точек, при котором текст, выводимый шрифтом 8×16, выглядит почти также, как в текстовом режиме. Вы можете изменить разрешение, выбрав одно из трех предложенных в примере значений константы GraphicsMode. При увеличении разрешения становится менее заметным «лестничный эффект», то есть линии кажутся более «гладкими», но снижается яркость изображения (из-за того, что точки стали меньше, а линии — тоньше) и хуже читается текст (вследствие уменьшения размера символов). Изменяя номер режима, не забудьте присвоить соответствующие значения константам, описывающим физическое разрешение экрана (ScreenLength и ScreenHeigth).

Листинг 4.4. Вывод на экран текста и линий в режиме 256 цветов с разрешением 640×480

IDEAL

Р386

LOCALS

MODEL MEDIUM

; Коды 256-цветных видеорежимов с линейной

; адресацией видеобуфера:

; 4101h – режим с разрешением 640×480 4103h – режим с разрешением 800×600

; 4105h – режим с разрешением 1024×768 GraphicsMode equ 4101h

; Логическая ширина строки в пикселах LogicalStringLength equ 1024

; Ширина зкрана в пикселах ScreenLength equ 640 : Высота экрана, строк ScreenHeigth equ 480

: Подключить файл мнемонических обозначений : кодов управляющих клавиш и цветовых кодов

Include "listl_03.inc"

; Подключить файл макросов

Include "listl_04.inc"

DATASEG

: Абсолютный адрес начальной точки для "пучка"

; цветных линий StartPixelAddress DD ?

; Текстовые сообщения Txtl

DB 0,19

DB "ТЕСТ 256-ЦВЕТНОГО РЕЖИМА ВИДЕОКОНТРОЛЛЕРА".0 Txt2

DB 2,22,"Вывод на экран текста, вертикальных,",0

DB 3,1В

DB "горизонтальных и диагональных цветных линий",0 AnyK

DB 29,29,"Нажните любую клавишу",0 ENDS

SEGMENT sseg para stack ‘STACK’

DB 400h DUP(?)

ENDS

CODESEG

;* Основной модуль програнны *

PROC Test256Mode

mov AX,DGROUP

mov DS.AX

mov [CS:MainDataSeg],AX

; Установить текстовый режин

mov AX,3 int lOh

; Установить режин пряной адресации паняти

call Initialization

; "Захватить" текстовый шрифт

cal1 GrabRusFont

; Установить видеорежин

call SetVESAVideoMode

; Отобразить текстовые сообщения

; Установить черный цвет фона

mov [DefaultBackground],BLACK

; Установить желтый цвет текста

mov [DefaultColor].YELLOW MGShowString Txtl

; Установить зеленый цвет текста

mov [DefaultColor],LIGHTGREEN MGShowText 2,Txt2 : Установить желтый цвет текста

mov [DefaultColor],YELLOW MGShowString AnyK

: Вычислить адрес начальной точки для пучка линий.

; Координаты точки (220,100)

; Умножить длину строки на номер строки (Y)

mov EAX.LogicalStringLength

mov EDX.100

Листинг 4.4(продолжение) mul EDX

: Прибавить номер колонки (X)

add ЕАХ,220 : Прибавить адрес видеобуфера

add ЕАХ,[LinearVideoBuffer] : Запомнить адрес начальной точки

mov [StartPixelAddress],ЕАХ : Начертить на экране горизонтальную белую

; линию с координатани (220,100)-(420.100) : Установить цвет линии

mov AL,WHITE : Записать адрес начальной

; точки в индексный регистр

mov EDI,[StartPixelAddress] : Задать длину линии в пикселах

mov СХ,200 @PL1:

mov [GS:EDI],AL ;нарисовать пиксел

inc EDI:перейти в следующую позицию

loop

@@L1

; Начертить вертикальную белую линию

; С координатами (220,100)-(220.300)

mov AL,WHITE

mov EDI,[StartPixelAddress]

mov CX,200 (affl.2:

mov [GS:EDI],AL

add EDI,Logi calStri ngLength loop

@@L2

; Начертить красную линию с координатани : (220,100)-(420.300) (под углон 45 градусов : к горизонтали)

mov AL,LIGHTRED

mov EDI.[StartPixelAddress]

mov CX.200 0PL3:

mov [GS:EDI],AL

add EDI, Logi cal Stri ngLengtM-1 loop

@@L3 : Начертить зеленую линию с координатами : (220.100)-(420.200) (под углон 27 градусов : к горизонтали)

mov AL.LIGHTGREEN

mov EDI,[StartPixelAddress]

mov CX.200/2

@@L4:

mov [GS:EDI].AL

inc EDI

mov [GS:EDI].AL

add EDI, Logi cal Stri ngLengtM-1 loop

@@L4 : Начертить синюю линию с координатами

: (220,100)-(320,300) (под углои 63 градуса

; к горизонтали)

mov AL.LIGHTBLUE

mov EDI,[StartPixelAddress]

mov CX,200/2

@@L5:

mov [GS:EDI],AL

add EDI,Logical StringLength

mov [GS:EDI].AL

add EDI.LogicalStringLength+1 loop

@@L5

; Ожидать нажатия любой клавиши call GetChar

; ВЫХОД ИЗ ПРОГРАММЫ

@@End:

; Установить текстовый режии

mov АХ.З int 10h

; Выход в DOS

mov AH,4Ch int 21h ENDP Test256Mode ENDS

: Подключить процедуры ввода данных и вывода на экран

; в текстовой режиме

Include "listl_02.inc"

; Подключить подпрограмму, переводящую сегментный

; регистр GS в режим линейной адресации

Include "list2_01.inc"

; Подключить набор процедур общего назначения,

; предназначенных для установки графических

; видеорежимов и работы в них

Include "list4_02.inc"

; Подключить набор процедур вывода текста,

; предназначенных для 256-цветных режимов

Include "list4_03.inc"

END

Примеры выполнения простых операций вывода для режимов группы HiColorl6 (5:6:5) приведены в листингах 4.5 и 4.6: листинг 4.5 содержит процедуры вывода символа и очистки экрана для режима HiColorl6, а листинг 4.6 — основную программу TestHi Col orMode, выполняющую те же операции, что и пример из листинга 4.4.

ПРИМЕЧАНИЕ

Обратите внимание на особенность режимов HiColor16, усложняющую процесс программирования: для кодирования зеленого цвета используется шесть двоичных разрядов, а для красного и синего — по пять.

Листинг 4.5. Процедуры вывода символа и очистки экрана для режимов HiColor с линейной адресацией видеобуфера

DATASEG

; Цвет текста в графическом режиме по умолчанию DefaultColor DW OFFFFh ;белый

; Цвет фона в графическом режиме по умолчанию DefaultBackground DW 0 ;черный ENDS

C0DESEG

;* ВЫВОД СИМВОЛА 8×16 НА ЭКРАН В ГРАФИЧЕСКОМ РЕЖИМЕ *

;*(для режимов HiColor 5:6:5)*

;* Все параметры передаются через регистры:*

;* AL – ASCII-код символа:*

;* DH – номер текстовой строки экрана;*

;* DL – номер текстовой колонки экрана;*

;* Используются цвет символов и цвет фона,*

;* заданные по умолчанию.*

PROC PutGraCharNEAR

pushDS pushad

movCX,[CS:MainDataSeg]

movDS.CX

eld

; Смещение символа от начала шрифта

movSI,offset Font8xl6

xorAH.AH

shlAX,4

addSI,AX

; Вычислить левый верхний угол символа

xorEBX,EBX

movBL.DH

shlEBX,15 ;умножить номер строки на 1024*32

xorDH.DH

shlDX,4 ;умножить номер столбца на 16

orBX,DX

movEDI,EBX

addEDI,[LinearVideoBuffer]

movBX,[DefaultColor]

movDX.[DefaultBackground]

movAH.16 ;счетчик строк маски буквы P@M0: lodsb

movСХ.8 ;счетчик точек в строке маски

Р@М1: rolAL.1

jcРРМ2

mov[GS:EDI],DX

jmp ремз

@@М2:

mov [GS:EDI],BX ааМЗ:

add EDI.2 loop P0M1

add EDI, 2*Log1 cal Stn ngLength-16 dec AH jnz P0MO

; Завершение процедуры

@@EndPutGraChar: popad pop DS

inc DL ret

ENDP PutGraChar

;* ОЧИСТКА ЭКРАНА В ГРАФИЧЕСКОМ РЕЖИМЕ * ;* (процедура параметров не имеет) *

PROC GC1earScreen NEAR pushad

; Умножить высоту экрана ScreenHeigth на логическую

; ширину строки

mov ЕСХ,ScreenHeigth shl ЕСХ.10 : Загрузить в индексный регистр линейный

; адрес видеопамяти

mov EDI,[LinearVideoBuffer]

; Заполнить видеопамять нулями

uiov АХ,0 ;черный цвет

@@NextPixels:

mov [GS:EDI],AX

add EDI.2

dec ECX

jnz

@@NextPixels

popad

ret

ENDP GC1earScreen ENDS

Листинг 4.6. Вывод на экран текста и линий в режиме HiColor16 с разрешением 640×480

IDEAL

РЗВ6

LOCALS

MODEL MEDIUM

; Коды видеорежииов HiColor (5:6:5) с линейной

; адресацией видеобуфера: : 4111h – режим с разрешением 640х4В0

Листинг 4.6(продолжение)

; 4114h – режим с разрешением 800×600

; 4117h – режим с разрешением 1024×768 GraphicsMode equ 4111h

; Логическая ширина строки в пикселах LogicalStringLength equ 1024

; Ширина экрана в пикселах ScreenLength equ 640

; Высота экрана, строк ScreenHeigth equ 480

; Подключить файл мнемонических обозначений

; кодов управляющих клавиш и цветовых кодов

Include "listl_03.inc"

; Подкпючить файп макросов

Include "listl_04.inc"

DATASEG

; Абсолютный адрес начальной точки для "пучка"

; цветных линий StartPixelAddress DD ?

; Текстовые сообщения Txtl

DB 0.30,"ТЕСТ РЕЖИМА HICOLOR".0 Txt2

DB 2,22."Вывод на экран текста, вертикальных,",О

DB 3.18

DB "горизонтальных и диагональных цветных линий".0 АпуК

DB 29,29,"Нажмите любую клавишу",0 ENDS

SEGMENT sseg para stack ‘STACK’

DB 400h DUP(?)

ENDS

CODESEG

;* Основной модуль программы *

PROC TestHiColorMode

mov AX.DGROUP

mov DS.AX

mov [CS:Mai nDataSeg],AX

; Установить текстовый режим

mov АХ.З int lOh

; Установить режмн прямой адресации памяти

call Initialization

; "Захватить" текстовый шрифт

call GrabRusFont : Установить видеорежим

call SetVESAVideoMode

; Отобразить текстовые сообщения

; Установить черный цвет фона

mov [DefaultBackground].0 : Установить бирюзовый цвет текста

mov [DefaultColor],7FFh MGShowString Txtl

; Установить зеленый цвет текста

mov [DefaultColor],7E0h MGShowText 2,Txt2

; Установить желтый цвет текста

mov [Defaulted or], OFFEOh MGShowString AnyK

; Вычислить адрес начальной точки для пучка линий.

; Координаты точки (220,100)

; Умножить длину строки на номер строки (Y)

mov ЕАХ,LogicalStringLength

mov EDX.100 mul EDX

: Прибавить номер колонки (X)

add ЕАХ. 220

; Умножить результат на 2 shl ЕАХ.1

: Прибавить адрес видеобуфера

add ЕАХ,[LinearVideoBuffer]

; Запомнить адрес начальной точки

mov [StartPixelAddress],ЕАХ : Начертить на экране горизонтальную белую : линию с координатами (220,100)-(420,100) : Установить цвет линии

mov AX.OFFFFh : Записать адрес начальной : точки в индексный регистр

mov EDI.[StartPixelAddress]

; Задать длину линии в пикселах

mov СХ,200

@@L1:

mov [GS:EDI],AX ;нарисовать пиксел

add EDI,2;перейти в следующую позицию

loop

@@L1 : Начертить вертикальную белую линию

; с координатами (220.100)-(220.300)

mov AX.OFFFFh ;белый

mov EDI,[StartPixelAddress]

mov СХ.200 0?L2:

mov [GS:EDI].AX

add EDI.LogicalStringLength*2 loop (sH?L2

; Начертить красную линию с координатами

; (220.100)-(420,300) (под углои 45 градусов

; к горизонтали)

9-231

Листинг 4.6 (продолжение)

mov AX,0F800h ;красный

mov EDI.[StartPixelAddress]

mov CX.200 »aL3:

mov [GS:EDI],AX

add EDI,(LogicalStringLength+l)*2 loop

@@L3

; Начертить зеленую линию с координатами

; (220.100)-(420,200) (под углом 27 градусов

; к горизонтали)

mov АХ.7E0h ;зеленый

mov EDI,[StartPixelAddress]

mov CX,200/2 0?L4:

mov [GS:EDI],AX

add EDI,2

mov [GS:EDI],AX

add EDI,(LogicalStringLength+l)*2 1oop

@@L4

; Начертить синюю линию с координатами : (220,100)-(320,300) (под углом 63 градуса

; к горизонтали)

mov AX.lFh ;синий

mov EDI,[StartPixelAddress]

mov CX.200/2 РЙ.5:

mov [GS:EDI].AX

add EDI,LogicalStringLength*2

mov [GS:EDI],AX

add EDI,(LogicalStringLength+l)*2 loop

@@L5

; Ожидать нажатия любой клавиши call GetChar

: ВЫХОД ИЗ ПРОГРАММЫ

@@End:

; Установить текстовый режим

mov АХ.З int 10h

; Выход в DOS

mov AH,4Ch int 21h ENDP TestHiColorMode ENDS

; Подключить процедуры ввода данных и вывода на экран

; в текстовом режиме

Include "listl_02.inc"

; Подключить подпрогранну, переводящую сегментный

; регистр GS в режим линейной адресации

Include "list2_01.inc"

: Подключить набор процедур общего назначения,

; предназначенных для установки графических

; видеорежимов и работы в них

Include "list4_02.inc" : Подключить набор процедур вывода текста,

; предназначенных для режимов HiColor

Include "list4_05.inc"

END

ПРИМЕЧАНИЕ

Для запуска примера из листинга 4.6 при разрешении 640×480 достаточно иметь видеоконтроллер с объемом памяти 1 Мбайт, а при более высоких разрешениях нужно 2 Мбайт.

Пример для режимов группы TrueColor32 (8:8:8:8) также состоит из двух модулей: листинг 4.7 содержит процедуры вывода символа и очистки экрана, а листинг 4.8 — основную программу TestTrue- ColorMode. Поскольку заранее неизвестно, поддерживает ли видеоконтроллер режим TrueColor32, и какой номер присвоен изготовителями контроллера этому режиму, приходится проводить поиск по всему списку режимов. Поиск осуществляется по заданным значениям констант ScreenLength и ScreenHeigth.

Листинг 4.7. Процедуры вывода символа и очистки экрана для режимов TrueColor32 с линейной адресацией видеобуфера

DATASEG

: Цвет текста в графическом режиме по умолчанию DefaultColor DD OFFFFFFh ;белый : Цвет фона в графическом режиме по умолчанию Default8ackground DD 0:черный

ENDS

CODESEG

;* ВЫВОД СИМВОЛА 8×16 НА ЭКРАН В ГРАФИЧЕСКОМ РЕЖИМЕ *

;*(для режимов HiColor 5:6:5)*

;* Все параметры передаются через регистры:*

;* AL – ASCII-код символа;*

;* DH – номер текстовой строки экрана:*

;* DL – номер текстовой колонки экрана;*

;* Используются цвет символов и цвет фона,*

;* заданные по умолчанию.*

PROC PutGraChar NEAR push DS pushad

mov CX,[CS:Mai nDataSeg]

mov DS.CX

Листинг 4.7 (продолжение) eld

: Смещение символа от начала шрифта

mov SI.offset Font8xl6

xor AH.AH

shl AX.4

add SI, AX

; Вычислить левый верхний угол символа xor EBX.EBX

mov BL.DH

shl EBX.16 ;уммо*ить номер строки ма 1024*64 xor DH.DH

shl DX,5 ;умно*ить номер столбца на 32 or BX.DX

mov EDI,EBX

add EDI,[LinearVideoBuffer]

mov EBX,[DefaultColor]

mov EDX,[DefaultBackground]

mov AH,16 ;счетчик строк маски буквы 6Ш): lodsb

mov СХ,В ;счетчик точек в строке иаски Р@М1: rol AL.1 jc

@@М2

mov [GS:EDI],EDX jmp

@@M3 P@M2:

mov [GS: EDI], EBX P@M3:

add EDI,4 loop

@@M1

add ED1,4*Logi calStri ngLength- 32 dec AH jnz P@M0

; Завершение процедуры

@@EndPutGraChar: popad

pop DS

inc DL ret

ENDP PutGraChar

;* ОЧИСТКА ЭКРАНА В ГРАФИЧЕСКОМ РЕЖИМЕ * ;* (процедура параметров не имеет) *

PROC GClearScreen NEAR pushad

; Умножить высоту экрана ScreenHeigth на логическую

; ширину строки

mov ЕСХ.ScreenHei gth shl ЕСХ,10

; Загрузить в индексный регистр линейный

; адрес видеопамяти

mov EDI,[LinearVideoBuffer] : Заполнить видеопамять нулями

mov ЕАХ,0 ;черный цвет

@@NextPixels:

mov [GS:EDI],ЕАХ

add EDI,4

dec ECX

jnz

@@NextPixels

popad

ret

ENDP GC1earScreen ENDS

Листинг 4.8. Вывод на экран текста и линий в режиме TrueColor32 с разрешением 640×480

IDEAL

Р386 LOCALS

MODEL MEDIUM

; Номер видеорежима заранее не известен GraphicsMode equ О

: Логическая ширина строки в пикселах LogicalStnrigLength equ 1024 , Ширина экрана в пикселах ScreenLength equ 640

; Высота экрана, строк ScreenHeigth equ 480

i

; Подключить файл мнемонических обозначений

; кодов управляющих клавиш и цветовых кодов

Include "listl_03 inc" , Подключить файл макросов

Include "listl_04.inc"

DATASEG

; Абсолютный адрес начальной точки для "пучка" : цветных линий StartPixelAddress DD ?

; Текстовые сообщения Txtl

DB 0,28,"ТЕСТ РЕЖИМА TRUEC0L0R32",0 Txt2

DB 2,22,"Вывод на экран текста, вертикальных,",0

DB 3,18

DB "горизонтальных и диагональных цветных линий",0 AnyK

DB 29,29,"Нажмите любую клавишу".0 ENDS

SEGMENT sseg para stack ‘STACK’

Листинг 4.8 (продолжение)

DB 400h DUP(?) ENDS

CODESEG

;* Основной модуль программы * ;*****************************

PROC TestTrueColorMode

mov AX.DGROUP

mov DS.AX

mov [CS:MainDataSeg],AX

; Установить текстовый режим

mov АХ.З int lOh

; "Захватить" текстовый шрифт

cal1 GrabRusFont

; Установить видеорежим

call SetTrueColor32

; Установить режим прямой адресации памяти

call Initialization

; Отобразить текстовые сообщения

; Установить черный цвет фона

mov [dword ptr DefaultBackground],0

; Установить фиолетовый цвет текста

mov [dword ptr DefaultColor].OFFOOFFh

MGShowString Txtl

; Установить зеленый цвет текста

mov [dword ptr DefaultColor],0FF00h

MGShowText 2,Txt2

; Установить желтый цвет текста

mov [dword ptr DefaultColor],OFFFFOOh

MGShowString AnyK

: Вычислить адрес начальной точки для пучка линий.

; Координаты точки (220,100)

; Умножить длину строки на номер строки (Y)

mov ЕАХ,LogicalStringLength

mov EDX,100 mul EDX

; Прибавить номер колонки (X)

add EAX,220

; Умножить результат на 4 shl ЕАХ,2

; Прибавить адрес видеобуфера

add EAX,[LinearVideoBuffer]

; Запомнить адрес начальной точки

mov [StartPixelAddress],ЕАХ

; Начертить на экране горизонтальную белую

; линию с координатами (220,100)-(420,100)

; Установить цвет линии

mov EAX.OFFFFFFh ;белый

; Записать адрес начальной

; точки в индексный регистр

mov EDI,[StartPixelAddress]

; Задать длину линии в пикселах

mov СХ,200

@@L1:

mov [GS:EDI],ЕАХ ;нарисовать пиксел

add EDI,4;перейти в следующую позицию

loop

@@L1

; Начертить вертикальную белую линию

; с координатами (220,100)-(220,300)

mov EAX.OFFFFFFh ;белый

mov EDI,[StartPixelAddress]

mov CX.200 0?L2:

mov [GS:EDI],EAX

add EDI,LogicalStringLength*4 loop

@@L2

; Начертить красную линию с координатами : (220,100)-(420,300) (под углом 45 градусов

; к горизонтали)

mov ЕАХ.OFFOOOOh ;красный

mov EDI.[StartPixelAddress]

mov CX.200 (ЭД-З:

mov [GS:EDI],EAX

add EDI,(LogicalStringLength+l)*4 loop (aOL3

; Начертить зеленую линию с координатами

; (220,100)-(420,200) (под углом 27 градусов : к горизонтали)

mov EAX,0FF00h ;зеленый

mov EDI.[StartPixelAddress]

mov СХ.200/2 0?L4:

mov [GS:EDI], ЕАХ

add EDI.4

mov [GS:EDI],EAX

add EDI,(LogicalStringLength+l)*4 loop

@@L4

; Начертить синюю линию с координатами

; (220,100)-(320,300) (под углом 63 градуса

; к горизонтали)

mov EAX.OFFh ;синий

mov EDI,[StartPixelAddress]

mov CX,200/2 Ж5:

mov [GS:EDI],EAX

add EDI,LogicalStringLength*4

mov [GS:EDI].EAX

add EDI,(LogicalStringLength+l)*4 loop

@@15

; Ожидать нажатия любой клавиши call GetChar

Листинг 4.8(продолжение)

; ВЫХОД ИЗ ПРОГРАММЫ

@@End: : Установить текстовый режин

mov АХ,3 int 10h : Выход в DOS

mov AH.4Ch int 21h ENDP TestTrueColorMode ENDS

: Подключить процедуры ввода данных и вывода на экран : в текстовой режиме

Include "1istl_02.inc"

; Подключить подпрограмму, переводящую сегментный

; регистр GS в режим линейной адресации

Include "list2_01.inc"

: Подключить набор процедур общего назначения,

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

Include "list4_02.inc" : Подключить набор процедур вывода текста. : предназначенных для режимов TrueColor32

Include "list4_07.inc"

END

ПРИМЕЧАНИЕ

Для запуска примера из листинга 4.8 необходим видеоконтроллер с объемом памяти не менее 4 Мбайт (в старых контроллерах с объемом памяти 1- 2 Мбайт в целях экономии вместо TrueColor32 использовался режим True- Color24).

Если сравнить примеры для разных типов видеорежимов, то становится очевидным, что при выводе текста и чертежей режимы HiColor и TrueColor не дают никаких преимуществ по сравнению с 256-цветными режимами. В то же время 256-цветные режимы экономно используют видеопамять (достаточно 1-2 Мбайт даже при высоком разрешении) и существенно превосходят все остальные типы режимов по скорости вывода информации (правда, только при использовании специальных алгоритмов, позволяющих выводить по четыре пиксела за одну операцию).

Пример использования алгоритма Брезенхема для рисования линии в 256-цветных режимах приведен в листингах 4.9 и 4.10. Процедура рисования линии EVGALine, приведенная в листинге 4.9, получена путем прямого перевода примера из книги Майкла Абраша [1]

с языка С на язык Ассемблер х86. Процедура использует две вспомогательные подпрограммы OctantO и Octantl для рисования линий в различных октантах. Процедура специально приведена в неопти- мизированном варианте (переменные хранятся в памяти, а не в регистрах), так как после оптимизации программа утрачивает свойство наглядности. Вызывающая (основная) программа TestLines256 из листинга 4.10 предназначена для тестирования процедуры рисования линии: она выводит четыре пучка линий различных цветов — белого, красного, синего и зеленого.

Листинг 4.9. Подпрограмма рисования линии по алгоритму Брезенхема для 256-цветных режимов

DATASEG

EVENвыравнивание смещения данных на 2

: Координаты начала линии

Х0DD ?

Y0DD ?

: Координаты конца линии

XIDD ?

Y1DD ?

: Длина линии no X и по Y

Del tax DD ?

DeltaY DD ?

: Направление рисования no X (1 – линия : прорисовывается слева направо. -1 – справа налево) XDirection DD ?

; Цвет линии Color

DB ?

EVENвыравнивание смещения данных на 2

: Внутренние переменные процедур рисования

DeltaYx2DD ?

DeltaYx2Mi nusDeltaXx2 DD ?

DeltaXx2DD ?

DeltaXx2Mi nusDeltaYx2 DD ?

ErrorTermDD ? ;ошибка накопления

PixelOffsetDD ?

ENDS

CODESEG

;* ПРОЦЕДУРА РИСОВАНИЯ ЛИНИИ В ОКТАНТАХ 0 И 3 * ;*С | Del -tax | >= DeltaY)*

PROC OctantO NEAR pushad

; Установить начальную ошибку накопления и значения.

; используемые во внутреннем цикле

Листинг 4.9(продолжение)

; (DeltaYx2 = 2*DeltaY)

mov EAX,[DeltaY]

shl EAX.l

mov [DeltaYx2],EAX

; (ErrorTerm = DeltaYx2 – DeltaX)

sub EAX.[DeltaX]

mov [E г гогТегш].ЕАХ

; (DeltaYx2Mi nusDeltaXx2 = DeltaYx2 – 2*DeltaX) sub EAX.[DeltaX]

mov [DeltaYx2Mi nusDeltaXx2],EAX

; Рисуем линию

: (PixelOffset=YO*LogicalStringLength+XO)

mov EAX,[Y0]

mov EDX,LogicalStringLength mul EDX

add EAX,[X0]

mov [PixelOffset], EAX : Рисуем первую точку линии

mov ЕВХ,[PixelOffset]

add EBX,[LinearVideoBuffer]

mov AL, [Col or]

mov [GS:EBX].AL

; Цикл, пока DeltaX>=0

@@NextDot:

: Проверить, не пора ли перейти на точку

; по оси Y

cmp [ErrorTerm],О jl @0AddError

; Сделать mar по Y

add [Pixel Offset],Logi calStri ngLength

; Увеличить ошибку накопления

mov EAX,[DeltaYx2Mi nusDeltaXx2]

add [ErrorTerm],EAX jmp

@@PutPixel

@@AddError:

; Увеличить ошибку накопления

mov EAX,[DeltaYx2]

add [ErrorTerm],EAX

@@PutPixel:

; Сделать mar по X

mov EAX.[XDirection]

add [PixelOffset], EAX

; Вывести очередную точку линии на экран

mov ЕВХ.[Pixel Offset]

add EBX,[LinearVideoBuffer]

mov AL, [Color]

mov [GS:EBX].AL

dec [DeltaX]

jnz

@@NextDot

popad ret

ENDP OctantO

;* ПРОЦЕДУРА РИС08АНИЯ ЛИНИИ В ОКТАНТАХ 1 И 2 * ;*С|Del tax[ < DeltaY)*

PROC Octantl NEAR pushad

: Установить начальную ошибку накопления и значения. : используемые во внутреннем цикле : (DeltaXx2 = 2*DeltaX)

mov ЕАХ,[DeltaX] shl EAX.l

mov [DeltaXx2].EAX

; (ErrorTerm = DeltaXx2 – DeltaY) sub EAX,[DeltaY]

mov [ErrorTerm],EAX

: (DeltaXx2Mi nusDeltaYx2 – DeltaXx2 – 2*DeltaY) sub EAX.[DeltaY]

mov [DeltaXx2Mi nusDeltaYx2],EAX

; Рисуем линию

; (Pixel0ffset=Y0*LogicalStringLength+XO):

mov EAX.[YO]

mov EDX.LogicalStringLength mul EDX

add EAX,[XO]

mov [Pixel Offset],EAX

; Рисуем первый пиксел

mov EBX,[PixelOffset]

add EBX,[Li nearVi deoBuffer]

mov AL,[Color]

mov [GS:E8X],AL

; Цикл, пока DeltaY>=0

@@NextDot:

; Проверить, не пора ли перейти на точку

; по оси X

cmp [ErrorTerm],О jl @0AddError : Сделать шаг по X

mov EAX,[XDirection]

add [PixelOffset],EAX : Увеличить ошибку накопления

mov ЕАХ.[DeltaXx2MinusDeltaYx2]

add [ErrorTerm],EAX jmp

@@PutPixel

; Увеличить ошибку накопления @0AddError:

mov EAX,[DeltaXx2]

Листинг 4.9 (продолжение)

add [ErrorTermj.EAX

@@PutPixel:

; Сделать шаг no Y

add [Pi xelOffset],Logi calStringLength

; Вывести очередную точку линии на экран

mov ЕВХ,[PixelOffset]

add EBX.[LinearV1deoBuffer]

mov AL,[Color]

mov [GS:EBX].AL

dec [DeltaY]

jnz

@@NextDot

popad

ret

ENDP Octantl

;* ПРОЦЕДУРА РИСОВАНИЯ ЛИНИИ ПО АЛГОРИТМУ БРЕЗЕНХЕМА * ;* Передача параметров выполняется через*

;* глобальные переменные:*

;* ХО, Y0 • координаты начальной точки;*

;* XI, Y1 – координаты конечной точки;*

;* Color – цвет линии.*

PROC EVGALine NEAR pushad

; Запомнить координаты линии в стеке push [ХО] push [Y0] push [XI] push [Yl]

; Если YO > Yl, поменять местами начальную

; и конечную точки линии,

mov EAX.[Y0] cmp EAX,[Y1] jbe

@@L0 xchg EAX,[Yl] xchg EAX.[YO]

mov EAX,[X0] xchg EAX,[XI] xchg EAX,[XO]

0GLO:

; Вычислить DeltaX

mov EAX.[XI] sub EAX, [XO]

mov [DeltaX],EAX

; Вычислить DeltaY

mov EAX.[Yl] sub EAX.[Y0]

mov [DeltaY],EAX

: Выбрать номер октанта и направление движения

mov[XDirection].l

movЕАХ.[DeltaX]

cmpЕАХ.О

jge@@L1

negЕАХ

mov[DeltaX],ЕАХ

mov[XDirection],-l

@@L1: cmpEAX,[DeltaY]

jle№L2

cal1OctantO

jmp@@End

№L2: callOctantl

; Восстановить координаты линии

@@End: pop [Yl] pop [XI] pop [YO] pop [XO] pop ad ret

ENDP EVGALine ENDS

Листинг 4.10. Рисование линий по алгоритму Брезенхема в режиме 256 цветов с разрешением 640×480

IDEAL

РЗВб

LOCALS

MODEL MEDIUM

: Коды 256-цветных видеорежимов с линейной

; адресацией видеобуфера:

4101h – режим с разрешением 640×480 : 4103h – режим с разрешением ВООхбОО

; 4105h – режим с разрешениеи 1024×768 GraphicsMode equ 4101h

; Логическая ширина строки в пикселах LogicalStringLength equ 1024 : Ширина экрана в пикселах ScreenLength equ 640 : Высота экрана, строк ScreenHeigth equ 480

: Подключить файл мнемонических обозначений

; кодов управляющих клавиш и цветовых кодов

Include "listl_03.inc"

; Подключить файл макросов

Include "listl_04.inc"

Листинг 4.10 (продолжение) DATASEG

: Текстовые сообщения

Txtl

DB 0,22."РИСОВАНИЕ ЛИНИЙ В 256-ЦВЕТНОМ РЕЖИМЕ",О

AnyK

DB 29.29,"Нажмите любую клавишу".О

ENDS

SEGMENT sseg para stack ‘STACK’

DB 400h DUP(?)

ENDS

CODESEG

;* Основной модуль программы *

• ‘A’AvAA А А А ‘to’to’to to totototo’tototo to toto to to to to to A to’to

PROC TestLines256

mov AX.DGROUP

mov DS.AX

mov [CS:MalnDataSeg],AX

; Установить текстовый режим

mov АХ.З int lOh : Установить режим прямой адресации памяти

call Initialization

; "Захватить" текстовый шрифт

cal1 GrabRusFont : Установить видеорежим

call SetVESAVideoMode

; Отобразить текстовые сообщения

; Установить черный цвет фона

mov [DefaultBackground].BLACK : Установить зеленый цвет текста

mov [Defaul tColor],LIGHTCYAN MGShowString Txtl

; Установить желтый цвет текста

mov [DefaultColor],YELLOW MGShowString AnyK

: Занести координаты начальной точки для пучка линий

mov [dword ptr X0J.320

mov [dword ptr Y0].240

; Нарисовать пучок белых линий

mov ЕАХ,[dword ptr XO]

add EAX.100

mov [dword ptr XI].EAX

mov EAX.[dword ptr YO] sub EAX.100

mov [dword ptr Y1].EAX

mov [Col or].WHITE

mov CX.50

@@NextWhiteLine:

callEVGALine

add[dword ptr Yl].4

loop@@NextWhiteLine

; Нарисовать пучок красных линий

movЕАХ.[dword ptr XO]

addEAX.100

mov[dword ptr XI].EAX

movEAX.[dword ptr Y0]

addEAX, 100

mov[dword ptr Y1].EAX

mov[Col or].LIGHTRED

movCX.50

@@NextRedLine:

callEVGALine

sub[dword ptr XI].4

loop@@NextRedLine : Нарисовать пучок зеленых линий

movЕАХ.[dword ptr XO]

subEAX.100

mov[dword ptr XI].EAX

movEAX,[dword ptr Y0]

addEAX.100

mov[dword ptr Y1],EAX

mov[Col or],LIGHTGREEN

movCX.50

@@NextGreenLine:

callEVGALine

sub[dword ptr Yl],4

loop@@NextGreenLine

; Нарисовать пучок синих линий

movЕАХ.[dword ptr X0]

subEAX. 100

mov[dword ptr XI],EAX

movEAX,[dword ptr Y0]

subEAX,100

mov[dword ptr Y1],EAX

mov[Col or].LIGHTBLUE

movCX.50

@@NextBlueLine:

callEVGALine

add[dword ptr XI].4

loop@@NextBlueLine

; Ожидать нажатия любой клавиши

callGetChar

; Установить текстовый режин

movАХ.З

int10h : Выход в DOS

movAH,4Ch

Листинг 4.10 (продолжение)

int 21h ENDP TestLines256 ENDS

; Подключить процедуры ввода данных и вывода на экран : в текстовом режиме

Include "listl_02.inc"

; Подключить подпрограмму, переводящую сегментный : регистр GS в режим линейной адресации

Include "list2_01.inc"

; Подключить набор процедур общего назначения,

; предназначенных для установки графических

; видеорежимов и работы в них

Include "list4_02.inc" : Подключить набор процедур вывода текста.

; предназначенных для 256-цветных режимов

Include "list4_03.inc"

: Подключить подпрограмму рисования линии по

; алгоритму Брезенхеиа для 256-цветных режимов

Include "list4_09.inc"

END

Пример использования алгоритма Брезенхема в режимах True- Color32 дан в листингах 4.11 и 4.12. Приведенная в листинге 4.11 процедура рисования линии EVGALine по сути та же самая, что и в листинге 4.9, но адаптирована для режимов TrueColor. Программа TestLinesTrueColor32, приведенная в листинге 4.12, не только тестирует процедуру рисования линии, но и демонстрирует один из приемов создания спецэффектов: при выводе пучка линий плавно меняется яркость, а линии размещаются впритирку друг к другу, создавая в результате иллюзию пропеллера.

ПРИМЕЧАНИЕ

Как уже было указано выше, для запуска программ, работающих в режиме TrueColor32, необходим видеоконтроллер, имеющий не менее 4 Мбайт памяти.

Листинг 4.11. Подпрограмма рисования линии по алгоритму Брезенхема для режима TrueColor32

DATASEG

EVENвыравнивание смещения данных на 2

; Координаты начала линии ХОDD ?

YODD ?

: Координаты конца линии

XIDD ?

YlDD ?

; Длина линии по X и по Y DeltaX DD ? DeltaY DD ?

; Направление рисования по X (1 – линия

; прорисовывается слева направо, -1 – справа налево) XDirection DD ?

; Цвет линии Color DD ?

EVENвыравнивание смещения данных на 2

; Внутренние переменные процедур рисования

DeltaYx2DD ?

DeltaYx2MinusDeltaXx2 DD ?

DeltaXx2DD ?

DeltaXx2Mi nusDeltaYx2 DD ?

ErrorTermDD ? ;ошибка накопления

PixelOffsetDD ?

ENDS

CODESEG

•* ПРОЦЕДУРА РИСОВАНИЯ ЛИНИИ В ОКТАНТАХ О И 3 * ;*С | Del taX | >= DeltaY)*

PROC OctantO NEAR pushad

; Установить начальную ошибку накопления и значения,

; используемые во внутренней цикле : (DeltaYx2 = 2*DeltaY)

mov ЕАХ.[DeltaY] shl EAX.l

mov [DeltaYx2],EAX

; (ErrorTerm = DeltaYx2 – DeltaX) sub EAX,[DeltaX]

mov [ErrorTerm],EAX

; (DeltaYx2MinusDeltaXx2 = DeltaYx2 – 2*DeltaX) sub EAX.[DeltaX]

mov [DeltaYx2MinusDeltaXx2],EAX

; Рисуем линию

; (Pi xelDffset=4*(Y0*Logi cal Stri ngLength+XO))

mov EAX.[YO]

mov EDX,LogicalStringLength mul EDX

add EAX,[XO] shl EAX,2

mov [Pixel Offset],EAX

; Рисуем первую точку линии

mov ЕВХ,[PixelOffset]

add ЕВХ,[Li nea rVi deoBuffer]

mov EAX,[Color]

Листинг 4.11 (продолжение)

mov [GS: EBX], ЕАХ

; Цикл, пока DeltaX>=0

@@NextDot:

: Проверить, не пора ли перейти на точку

; по оси Y

cmp [ErrorTerm] .0 jl

@@AddError : Сделать шаг по Y

add [PixelOffset].Logi calStringLength*4

; Увеличить ошибку накопления

mov ЕАХ,[DeltaYx2Mi nusDeltaXx2]

add [ErrorTerm],EAX jmp

@@PutPixel

@@AddError:

; Увеличить ошибку накопления

mov EAX,[DeltaYx2]

add [ErrorTerm],EAX

@@PutPixel:

; Сделать шаг по X

mov EAX,[XDi recti on]

add [PixelOffset],EAX

: Вывести очередную точку линии на экран

mov EBX,[PixelOffset]

add EBX,[LinearVideoBuffer]

mov EAX,[Color]

mov [GS:EBX],EAX

dec [DeltaX]

jnz

@@NextDot

popad

ret

ENDP OctantO

;* ПРОЦЕДУРА РИСОВАНИЯ ЛИНИИ В ОКТАНТАХ 1 И 2 * ;*(|DeltaX| < DeltaY)*

PROC Octantl NEAR pushad

; Установить начальную ошибку накопления и значения,

; используеиые во внутренней цикле : (DeltaXx2 = 2*DeltaX)

mov ЕАХ,[DeltaX] shl EAX.l

mov [DeltaXx2],EAX

; (ErrorTerm = DeltaXx2 – DeltaY) sub EAX.[DeltaY]

mov [ErrorTerm].EAX

; (DeltaXx2MinusDeltaYx2 = DeltaXx2 – 2*DeltaY) sub EAX.[DeltaY]

mov [DeltaXx2MinusDeltaYx2],EAX

; Рисуем линию

; (Pixel0ffset=4*(Y0*LogicalStringLengtM-X0));

mov EAX, [YO]

mov EDX,LogicalStringLength mul EDX

add EAX,[XO] shl EAX,2

mov [PixelOffset],EAX

; Рисуем первый пиксел

mov ЕВХ,[PixelOffset]

add EBX,[LinearVideoBuffer]

mov EAX,[Color]

mov [GS:EBX],EAX

; Цикл, пока DeltaY>=0

@@NextDot:

; Проверить, не пора ли перейти на точку

; по оси X

cmp [ErrorTerm],О jl @0AddError : Сделать шаг по X

mov ЕАХ,[XDirecti on]

add [PixelOffset],EAX

; Увеличить ошибку накопления

mov EAX,[DeltaXx2MinusDeltaYx2]

add [ErrorTerm],EAX jmp

@@PutPixel : Увеличить ошибку накопления

@@AddError:

mov EAX,[DeltaXx2]

add [ErrorTerm],EAX

@@PutPixel:

; Сделать шаг no Y

add [PixelOffset],LogicalStringLength*4

; Вывести очередную точку линии на экран

mov ЕВХ,[PixelOffset]

add EBX,[LinearVideoBuffer]

mov EAX,[Color]

mov [GS:EBX],EAX

dec [DeltaY]

jnz

@@NextDot

popad

ret

ENDP Octantl

;* ПРОЦЕДУРА РИСОВАНИЯ ЛИНИИ ПО АЛГОРИТМУ БРЕЗЕНХЕМА * ;* Передача параметров выполняется через , * ;* глобальные переменные:*

;* XO, Y0 – координаты начальной точки;*

Листинг 4.11 (продолжение)

;* XI, Y1 – координаты конечной точки;*

;* Color – цвет линии.*

PROC EVGALine NEAR pushad

; Запомнить координаты линии в стеке push [XO] push [YO] push [XI] push [Yl]

; Если YO > Yl, поменять местами начальную : и конечную точки линии,

mov ЕАХ,[YO] cmp EAX,[Y1] Jbe

@@L0 xchg EAX,[Y1] xchg EAX,[YO]

mov EAX,[XO] xchg EAX,[XI] xchg EAX,[XO]

МЧ.0:

; Вычислить DeltaX

mov ЕАХ,[XI] sub EAX,[X0]

mov [DeltaX],EAX

; Вычислить DeltaY

mov EAX,[Y1] sub EAX,[YO]

mov [DeltaY],EAX

; Выбрать номер октанта и направление движения

mov[XDirecti on],1*4

movEAX,[DeltaX]

cmpEAX.O

jge@@L1

negEAX

mov[DeltaX],EAX

mov[XDirecti on],-1*4

cmpEAX. [DeltaY]

jle@PL2

callOctantO

jmp@@End

@@L2: callOctantl

; Восстановить координаты линии PPEnd: pop [Yl] pop [XI] pop [YO] pop [XO]

popad ret

ENDP EVGALine ENDS

Листинг 4.12. Рисование линий по алгоритму Брезенхема в режиме TrueColor32 с разрешением 640×480

IDEAL

РЗВб

LOCALS

MODEL MEDIUM

; Нонер видеорежина заранее не известен GraphicsMode equ О

: Логическая ширина строки в пикселах LogicalStringLength equ 1024

; Ширина экрана в пикселах ScreenLength equ 640

; Высота экрана, строк ScreenHeigth equ 480

: Подключить файл иненонических обозначений

; кодов управляющих клавиш и цветовых кодов

Include "listl_03.inc"

; Подключить файл иакросов

Include "listl_04.inc"

DATASEG

: Текстовые сообщения

Txtl

DB 0.23,"РИСОВАНИЕ ЛИНИЙ В РЕЖИМЕ TRUECDLOR’.O

АпуК

DB 29,29,"Нажиите любую клавишу",О

ENDS

SEGMENT sseg para stack ‘STACK’

DB 400h DUP(?)

ENDS

CODESEG

;* Основной нодуль програины *

• ‘A"A"A"A А А А Л A1 AА "к ft Jc"k’k fcfcit’ic Jr A

PROC TestLi nesTrueColor32

mov AX,DGR0UP

mov DS.AX

mov [CS:Mai nDataSeg],AX

; Установить текстовый режии

mov АХ.З int lOh

; "Захватить" текстовый шрифт cal1 GrabRusFont

Листинг 4.12(продолжение)

; Установить видеорежин

call SetTrueColor32

; Установить режин пряной адресации паняти

call Initialization

; Отобразить текстовые сообщения

: Установить черный цвет фона

mov [dword ptr DefaultBackground],0

; Установить тенно-желтый цвет текста

mov [dword ptr Defaulted or], OEOBOOOh MGShowStri ng Txtl

; Установить желтый цвет текста

mov [dword ptr DefaultColor],0FFFF00h MGShowString AnyK

: Занести координаты начальной точки для пучка линий

mov[dword ptr Х0],320

mov[dword ptr Y0L240

; Нарисовать пучок белых линий

movЕАХ,[dword ptr ХО]

addЕАХ,127

mov[dword ptr XI],EAX

movEAX,[dword ptr YO]

subEAX, 127

mov[dword ptr Y1],EAX

mov[dword ptr Color],0 ;OFFFFFFh

movCX,254

@@NextWhiteLine:

callEVGALine

add[dword ptr Yl],l

add[dword ptr Color],010101h

loop@@NextWhiteL1ne

; Нарисовать пучок красных линий

movЕАХ.[dword ptr XO]

addEAX, 127

mov[dword ptr XI],EAX

movEAX, [dword ptr YO]

addEAX,127

mov[dword ptr Y1],EAX

mov[dword ptr Col or],0 ;0FF0000h

movCX.254

@@NextRedLi ne:

callEVGALine

sub[dword ptr XI]. 1

add[dword ptr Color],010000h

1oop@@NextRedLi ne

; Нарисовать пучок зеленых линий

movЕАХ,[dword ptr XO]

subEAX,127

mov[dword ptr XI],EAX

movEAX,[dword ptr YO]

addEAX,127

mov[dword ptr Y1],EAX

mov[dword ptr Col or],0 ;0FF00h

movCX.254

@@NextGreenLine:

callEVGALine

sub[dword ptr Yl],1

add[dword ptr Color],0100h

loop@@NextGreenLine : Нарисовать пучок синих линий

movЕАХ,[dword ptr XO]

subEAX,127

mov[dword ptr XI],EAX

movEAX,[dword ptr YO]

subEAX.127

mov[dword ptr Y1],EAX

mov[dword ptr Col or],0; OFFh

movCX.254

@@NextBlueLine:

callEVGALine

add[dword ptr XI].1

add[dword ptr Col or],1

1oopPPNextBlueLi ne

: Ожидать нажатия любой клавиши

cal1 GetChar

; Установить текстовый режии

mov АХ.З int 10h

; Выход в DOS

mov AH,4Ch int 21h ENOP TestLi nesTrueColor32 ENDS

; Подключить процедуры ввода данных и вывода на экран : в текстовой режиие

Include "listl_02.inc"

: Подключить подпрограмму, переводящую сегиентный

; регистр GS в режии линейной адресации

Include "list2_01.inc"

; Подключить набор процедур общего назначения,

; предназначенных для установки графических

; видеорежииов и работы в них

Include "list4_02.inc"

; Подключить набор процедур вывода текста.

; предназначенных для режимов TrueColor32

Include "list4_07.inc"

Листинг 4.12 (продолжение)

; Подключить подпрограмму рисования линии по

; алгоритму Брезенхема для режимов TrueColor32

Include "list4_ll.inc"

END

Источник: Кулаков В. К90 Программирование на аппаратном уровне: специальный справочник (+дискета). 2-е издание. — СПб.: Питер, 2003. — 847 е.: ил.

По теме:

  • Комментарии