Вывод текста в режиме 256 цветов | Сергей Андрианов | 17.12.2001 |
|
14k | |
Мир ПК, #12/2001
Вывод текста в режиме 256 цветовСергей Андрианов17.12.2001
В статье «Палитра VGA: управление цветом» было рассказано о том, как правильно вывести спрайт на экран. Теперь настала очередь разобраться с текстом. Нетрудно догадаться, что единственный способ его вывода на экран — прорисовка каждой буквы по точкам, т. е. здесь применяется та же самая технология, которая уже была рассмотрена на примере отображения спрайтов. Самый универсальный вариант — выводить каждую букву как спрайт, тем более что при этом можно применить красивые многоцветные буквы различного размера. Однако, во-первых, на экране с разрешением 320x200 точек не очень-то развернешься с крупными шрифтами, а при использовании мелких трудно получить что-нибудь более удачное, чем стандартный шрифт. Во-вторых, даже при размере символа 8x8 точек для хранения одного шрифта придется отвести 16 Кбайт оперативной памяти. И в-третьих, такие шрифты нужно самостоятельно рисовать, что при 256 символах нелегкий труд, да и довольно бессмысленный для небольшой игрушки. Поэтому в качестве альтернативы пойдем по самому простому и наименее ресурсоемкому пути и выберем стандартный шрифт, который ничто не мешает сочетать со спрайтовыми. В VideoBIOS компьютера помещена таблица со шрифтами разных размеров: 8x8, 8x14 и 8x16 точек. В России они, как правило, хранятся в теле резидентной программы, проводящей русификацию. Будем работать с самым «экономичным» из них — 8x8 точек, но для этого нужно знать адрес той ячейки памяти, с которой начинается его размещение. Этот адрес можно получить с помощью функции VideoBIOS (см. листинг 1). Для его хранения предусмотрена переменная FontTable. Ее значение ставится в блоке инициализации модуля, и тогда не требуется вызывать никаких дополнительных процедур, а шрифты станут доступны, начиная с первой строки основной программы. Надо сказать, что память при этом не расходуется (не считая 4 байт на указатель), поскольку используются шрифты, загруженные в ОЗУ. Итак, приступим к выбору цветов для символов и фона. Вопрос не такой уж простой, каким кажется на первый взгляд. Дело в том, что после установки палитры в первых 16 регистрах уже не будет тех цветов, к которым все привыкли: 0 — черный, 1 — синий, 2 — зеленый и т. д. Конечно, можно смириться с этим и просмотреть большую простыню1 с описанием всех 256 цветов, чтобы отобрать самый подходящий. Правда, для работы все равно придется ограничиться таблицей с номерами все тех же хорошо знакомых 16 цветов, а раз так, не проще ли поручить компьютеру конвертировать привычные для нас номера в номера рабочей палитры. Однако тогда мы уже не сможем применять для отображения текста остальные 240 цветов, но так ли уж велика эта потеря? Мне, например, более симпатичен именно такой вариант. У редактора Paint, с помощью которого рисовались спрайты для нашей программы, есть своя любимая палитра. Если создавать картинку с нуля или преобразовать полноцветное (24-разрядное с 16 млн. цветов) изображение в палитровое (8-разрядное 256-цветное), то этот редактор будет работать с одной и той же палитрой. Хотя ее цвета могут оказаться не самыми оптимальными для решения нашей задачи, есть уверенность, что все выполненные изображения будут воспроизводиться на экране в правильных цветах. Номера цветов палитры Paint, наиболее близкие к стандартным 16, хранятся в массиве Colors нашей программы. Если 16 цветов все-таки будет не хватать, длину этого массива можно увеличить. На нулевом месте записан номер черного цвета, на первом — синего и т. д. Если вы выберете какую-либо другую палитру, то цифры придется подкорректировать. Можно, конечно, подбор цветов поручить и компьютеру, но тогда такую процедуру придется вызывать только после установки палитры. Впрочем, этот блок позволяется разместить и в модуле программы, устанавливающем палитру, однако мне хотелось сделать так, чтобы все модули были независимы друг от друга. Модуль вывода изображения на экран в режиме 256 цветов содержит следующее:
Как уже было сказано, буквы выводятся по одной точке, каждой из которых на экране отводится 1 байт, а вот в шрифтах они лежат гораздо компактнее: на одну точку приходится один бит. Весь горизонтальный ряд точек помещается в одном байте, а вся буква — в восьми. При отрисовке буквы перед записью байта в видеопамять проверяется, что находится в нужном бите таблицы шрифтов: 0 или 1. В нашем примере будем выводить надписи в каждом кадре, что более наглядно. Чтобы посмотреть, как работает описанный модуль, следует включить его имя в директиву uses, описать дополнительную типизированную константу TextColor : byte = 0 и вставить фрагмент, приведенный в листинге 2, между вызовами процедуры отрисовки спрайта PutSprite и процедуры ожидания луча обратного хода WaitVerticalRetrace. На экране должна появиться переливающаяся разными цветами надпись, одна половина которой отображается на непрозрачном фоне, а другая — на прозрачном. Однако за простоту и нетребовательность к ресурсам приходится платить: предлагаемый способ вывода текста не обладает свойствами спрайта и портит под ним фон. Так что если текст требуется часто перерисовывать, то следует либо самому заботиться о сохранении фона, либо задать его непрозрачным. листинг 1interface { установка параметров вывода текста } procedure SetTextParm(color,bkcolor,typetext:byte); { color - цвет текста } { bkcolor - цвет фона } { typetext = 0 - прозрачный фон } { typetext = 1 - непрозрачный фон } { запрос текущих параметров } procedure GetTextParm(var color,bkcolor,typetext:byte); {вывод текста по координатам x,y (верхний левый угол)} procedure PutText(x,y:word;text:string); {вывод символа по координатам x,y (верхний левый угол)} procedure PutChar(x,y:word;chr:char); implementation uses dos; type FTType = array[0..255,0..7]of byte; {для шрифта} const Colors : array[0..15]of byte = ( 0, 2, 20, 22,160,162,172,182, 109,111,125,127,237,239,253,255); {цвета, соответствующие номерам 0-15} var FontTable : ^FTType; {таблица шрифта} Color1,bkColor1 : byte; {номера <стандартных> цветов текста и фона} Color2,bkColor2 : byte; {номера цветов текста и фона в выбранной палитре} TextType : byte; {способ вывода (прозрачно или нет)} procedure SetTextParm(color,bkcolor,typetext:byte); begin Color1 := color; bkColor1 := bkcolor; TextType := typetext; Color2 := Colors[Color1]; bkColor2 := Colors[bkColor1]; end; procedure GetTextParm(var color,bkcolor,typetext:byte); begin color := Color1; bkcolor := bkColor1; typetext := TextType; end; procedure PutText(x,y:word;text:string); var i:word; begin if(byte(text[0])>0)then for i := 1 to byte(text[0]) do putchar(x+8*(i-1),y,text[i]) end; procedure PutPixel(x,y:word;c:byte); {вывод точки} begin mem[SegA000:x+y*320] := c; end; function getpixel(x,y:word):byte; {запрос цвета точки} begin getpixel := mem[SegA000:x+y*320]; end; procedure putchar(x,y:word;chr:char); var i,j,k,l : word; cc,bb : byte; begin l := byte(chr); case TextType of 0: for i := 0 to 7 do { прозрачный фон } for j := 0 to 7 do if (FontTable^[l,i] and (1 shl (7-j)) <> 0) then putpixel(x+j,y+i,Color2); 1: for i := 0 to 7 do { непрозрачный фон } for j := 0 to 7 do if (FontTable^[l,i] and (1 shl (7-j)) <> 0) then putpixel(x+j,y+i,Color2) else putpixel(x+j,y+i,bkColor2); end; end; var r : registers; begin {инициализация - получаем адрес таблицы шрифтов} r.ax := $1130; r.bh := 3; intr($10,r); FontTable := ptr(r.es,r.bp); Color1 := 15; {заносим величины по умолчанию} bkColor1 := 0; TextType := 1; Color2 := Colors[Color1]; bkColor2 := Colors[bkColor1]; end. листинг 2inc(TextColor); SetTextParm(TextColor div 16, (TextColor + 48) div 16,1); PutText(56,16,'Демонстрационная'); SetTextParm(TextColor and $F,0,0); PutText(192,16,'программа'); Мир ПК, #12/2001 Постоянный адрес статьи: http://www.osp.ru/pcworld/2001/12/098.htm | ||