2. 5. Трехмерная растровая графика.
Мы рассмотрели широкие возможности применения копирования
растровой и цветовой составляющих с помошью команды XOR. Безус-
ловно. этот метод позволяет достичь важных результатов.- но на-
верное этот метод не единственный. И действительно, существует
ведь еше копирование с помошью логических команд AND (И) и OR
(ИЛИ). Надо только в процедуре, приведенной в разделе 2.4 заме-
нить команду XOR (HL) на AND (HL) или на OR (HL). сколько же
всего возможно различных сочетаний при копировании растровой
графики вы можете увидеть на нижеприведенной схеме.
Всего возможны 3»4*2 = 24 сочетания. Конечно, такое много-
образие нам никак не рассмотреть на страницах данной книги, но
в этом, по-видимому, и нет необходимости, ведь главное - ука-
зать на приемы и подходы, а дальше читатель сам может развивать
свое мастерство и изобретать новые способы. а мы же сейчас
остановимся на одной из областей растровой графики, в которой
нашла свое применение другая логическая функция - OR. Речь пой-
дет о трехмерной растровой графике и мы опять вспомним програм-
му "Knieht Lore" Фирмы ULTIMATE, хотя вместо нее можно было бы
указать любую из многих сотен программ, в которых использован
аналогичный прием.
Взгляните на рисунок 7. что Вам напоминает это изображе-
ние? Вряд ли оно похоже на что-то более менее содержательное.
А если его же напечатать на черном фоне экрана, как
показано на рис. 8? Совсем другое дело, не правда ли?
да. это тот самый элементарный блок, из которых построен
замок злого волшебника. Блок, как видите, трехмерный, но пусть
Вас это не тревожит - шаблон блока (рис. 9) самый обычный раз-
мером 3X3 знакоместа. Многое можно изобразить на экране с
помошью таких очень простых шаблонов.
Но. коли уж мы заговорили об имитации трехмерного игрового
пространства, нам надо рассмотреть и то. как из таких элемен-
тарных блоков строится трехмерная конструкция. Все очень прос-
то - эти блоки должны печататься со смешением. На рис. 10 пока-
зана простейшая конструкция из трех блоков (А.В.С).
При таком наложении шаблона на шаблон произойдет конфликт
между пиксельной конструкцией этих шаблонов. Посмотрите на
Рис. 11. что происходит, если накладывать их друг на друга про-
стым копированием.
Проблему представляют черные углы по диагонали шаблона.
При наложении черных выключенных пикселов на белые включенные
можно получить белые только если пользоваться наложением по XOR
или по OR. т. к. только для этих функций
1 OR О =1
1 XOR О
Вместе с тем, нам не удается воспользоваться и командой
xor. т. к. при этом наложение белого на белое даст черное пятно.
В этом*случае нас выручает команда or. Как видите, при
таком наложении все в порядке (Рис. 13).
Рис. 13
Конечно, кое-что при таком подходе мы и теряем. Например,
мы теряем возможность испольэрвать печать того же самого шаб-
лона еше раз. чтобы выполнить стирание без искажения содержимо-
го фона. Но это для нас и не страшно, ведь по сути дела здесь
Фоном является просто чистый черный экран, а когда мы печатали
один блок поверх другого, мы печатали Фактически один шаблон
поверх другого шаблона, а не поверх Фона. Восстановить простой
чистый черный Фон очень просто, напечатав пустой шаблон разме-
ром 3X3 знакоместа, что не труднее, чем повторять печать того
же самого шаблона.
У нас могут быть проблемы с цветовыми атрибутами. Но. про-
стите. а где в игровых программах с трехмерной графикой приме-
няют более двух цветов? Если это и делают, то только по полям
игрового поля, а не на основном игровом экране.
Итак, мы пришли к еше одному основополагающему выводу:
Вывод четвертый: Если мы накладываем шаблон на Фоновую
картинку, то лучше пользоваться командой XOR. Если мы
накладываем шаблон на шаблон, то лучше пользоваться
командой OR, Фоновую картинку упростить до минимума, а
от применения палитры цветов воздержаться.
i. б. Упаковка экранной информации.
Здесь под словом "упаковка" мы понимаем не компрессию изо-
бражения по принципу выявления и устранения последовательностей
повторяющихся байтов. Речь идет о том. что если в программе со-
тни экранов, то нужны какие-то другие приемы их упаковки, на-
пример создание "карты" для каждого экрана. Рассмотрим рис. 14.
Здесь показана конструкция одной типовои комнаты средневе-
кового замка. Все содержимое этой комнаты в трехмерном про-
странстве можно представить как бы состоящим из элементарных
кубических блоков размером г X 2 X 2 знакоместа каждый (Рис.9),
эти блоки на плоскость проецируются в виде плоских шаблонов
размером 3x3 знакоместа. Конечно же при создании комнаты мо-
гут быть использованы блоки самого разного вида и самых разных
свойств (например дверные блоки служат для прохода в другие
комнаты), и нам выгоднее хранить не картинку каждой комнаты, а
ее раскладку на блоки с указанием того, какой блок где находит-
ся.
В этом случае всю нашу комнату можно представить, напри-
мер. как набор из 9 X 7 X 5 блоков, те в виде последователь-
ности длинои всего 315 байт В каждом байте стоит номер блока.
который здесь должен быть поставлен В тех местах (а их боль-
шинство), где нет вообше ничего, можно поставить ноль. Разуме-
ется. большинство блоков повторяется и если теперь скомпресси-
ровать карту данной комнаты, то окажется, что на ее хранение
достаточно 15-20 байтов и теперь ее можно заархивировать вме-
сте с другими комнатами в единый длинный Файл, из которого мож-
но по номеру комнаты в любой момент извлечь ее "карту", деком-
прессировать и напечатать, вот так и получается, что в програм-
ме "Head over Heels" программистам удалось заложить более 300
очень непростых экранов, принадлежащих к разным замкам, всего
лишь в 5 с небольшим килобайт информации.
2. 7. Архивация данных.
Архивация данных - это не просто компрессия, это еше и
объединение скомпрессированных изображений в единый архив
(библиотеку) в заданном Формате, чтобы потом дезархивируюшая
процедура могла найти нужное изображение, разархивировать его и
передать на экран.
Конечно, архивировать можно не толко шаблоны изображений,
но и карты комнат и текстовые сообщения и экраны и многие дру-
гие данные. Разные объекты могут, в принципе, требовать разного
подхода, но мы остановимся на одном примере и рассмотрим весь
цикл подготовки библиотеки шаблонов для будущей программы.
Этот цикл состоит из следующих этапов:
1. Подготовка шаблонов изображений с помошью графического
редактора или другой доступной программы и отгрузка их на
ленту.
i
2. Поочередная загрузка шаблонов, компрессирование их и
выгрузка на ленту в виде единого Файла в заданном формате.
3. Подготовка дезархивируюшеи процедуры для включения ее в
состав будушей программы.
Рассмотрим требования к программам архивации и дезархива-
шш К архивирующей процедуре никаких особых требовании нет
Нам не очень важно ее быстродействие и нет никаких проблем с
объемом занимаемой памяти. Архивация данных является просто
техническим приемом, которым Вы можете заниматься в удобное
Вам время не спеша. Единственное требование к компрессирующей
приедуре - это то, что желательно иметь на выходе код как можно
меньшего размера, есле это не слишком скажется на быстродейст-
вии дезархивируюшей процедуры, ведь можно сделать такое много-
I
ступенчатое компрессирование, при котором дезархивируюшая про-
цедура будет работать слишком медленно. Но так или иначе, а
выбор во всех случаях за Вами и никому, кроме Вас лучше не
известны требования, которые Вы предъявляете к своей будущей
программе и Вы сами определитесь, в какой степени Вам нужно
быстродействие и насколько напряженно обстоит дело с объемом
доступной памяти.
К дезархивируюшей процедуре предъявляются очень жесткие
требования. Она работает в составе вашей программы и потому
должна и занимать минимальный объем памяти и работать как можно
быстрее. Конечно, Вы понимаете, что это зависит от алгоритма,
по которому она работает и, тем самым, связано с принятым Фор-
матом данных и с методом компрессии.
2. 7. 1. Нетодика компрессии.
Принципов компрессии данных много. Для текстовых данных
лучше подходят одни приемы, для числовых - другие. Графические
данные характеризуются высокой степенью повторяемости одинако-
вых байтов и потому здесь наиболее широко применяется прием,
когда компрессирующая программа проверяет количество таких по-
второв и после каждого байта, принятого из источника, ставит
число, указывающее на количество повторений, например:
Отводить первые два байта на указание длины сжатого шабло-
на нам необходимо для того, чтобы при дезархивации программа
могла найти начало нужного шаблона по его номеру.
В книге "Элементарная графика" мы рассмотрели несложную
пропедуру для компрессирования экранов. Здесь можно было бы
воспользоваться ею же, но. к сожалению, есть существенные отли-
чия. Дело в том. что там нам хорошо известны были и начало и
конец исходного Файла ото экранный Файл) здесь же их надо вво-
дить и хранить. Поэтому регистров обшего назначения ВС. DE и HL
нам уже не хватает, приходится привлекать к работе индексные
регистры процессора - IX и IY. Впрочем, это ведь только пример
и Вы сможете сами переделать процедуру так. как Вам будет
удобно.
Для создания процедуры компрессии файла шаблонов решим для
себя, что регистровая пара IX у нас будет указывать на байт
источника, регистровая пара IY - на байт приемника, регистровая
пара ВС будет служить счетчиком просмотренных байтов источника,
а регистр l будет служить счетчиком коэффициента повтора одина-
ковых байтов. При этом здесь возможны два варианта, иногда при
компрессии экранов целесообразно подсчитывать коэффициент пов-
тора в пределах до 65535. т. е. под него выделяют не регистр, а
регистровую пару и в сжатом Файле под каждый коэффициент отво-
дятся по два байта. Такой подход дает ощутимый выигрыш, когда
речь идет о компрессии экрана целиком, да к тому же если он не
очень заполнен информацией. В нашем случае, когда речь идет
только о компрессии шаблонов, лучше под счетчик повторов выде-
лять только один регистр, т. к. размеры шаблонов обычно невели-
ки и здесь практически не встретятся коэффициенты повторов
больше, чем 255. регистр А используем для хранения текущего
байта, принятого из источника, а регистр Е для хранения сравни-
ваемого с ним очередного байта с целью выявления повтора.
Для нашей процедуры нам потребуются программные переменные
BEGIN - адрес начала Файла шаблонов в памяти (адрес источника):
STORE - адрес начала скомпрессированного файла шаблонов (адрес
приемника).
Тогда процедура компрессии Файла шаблонов может выглядеть,
например так:
PUSH IX сохранение регистров на стеке.
PUSH IY ;
LD IX. BEGIN ;Адрес начала Файла шаблонов.
LD ВС. (BEGIN) : Длина шаблона.
INC IX
INC IX
DEC ВС ;Уменьшили длину источника на
DEC ВС :два байта (в них хранилась сама
;эта длина).
ld iy. store ;Адрес начала скомпрессированного
: шаблона.
INC IY ;Пропускаем два байта для того.
INC IY ; чтобы впоследствии в них
; подставить длину скомпрессирован-
; ного шаблона.
RETURN LD L.01 ;Инициализация счетчика повторов.
ld a. (ix+0) ; приняли текущий байт.
AGAIN INC IX ;И перешли к следующему.
DEC ВС ;Уменьшаем счетчик источника.
PUSH AF ;освобождаем регистр А и выполняем
LD А.С ;проверку на конец источника.
OR В
jr z. end ;Если весь источник просмотрен, то
; выход через метку end.
POP AF ; Восстановление регистра А.
LD Е. (1Х*0) .-Очередной байт приняли в
; регистр Е.
CP Е :И сравнили его с предыдущим в А.
JR NZ.PASS .-Если нет повтора, то обход на
: PASS.
INC L :Если есть повтор, то наращиваем
;счетчик повторов L.
JR NZ.AGAIN ; И переходим для анализа
;следующего байта источника.
dec l ; Если счетчик обнулялся, т. е.
;переполнился, уменьшаем его на
;единицу и перестаем наращивать.
; в качестве коэффициента повтора
;будет взято число 255.
PASS LD (IY+O). А : Перенесли байт из источника
; в приемник.
IHC IY ;Указатель в приеннике переставили
; вверх.
LD A. L ;Ввели коэффициент повтора.
LD (IY+0).А .отправили его в приемник.
IHC IY ; Указатель приемника - вверх.
JR RETURN ; возврат для обработки очередного
; байта.
END POP AF ; Первым делом надо восстановить
; баланс на стеке, т. к. выход на
; END происходил после команды
;PUSH AF. для которой не было
;соответствующей команды POP AF.
LD (IY+O).А ;Последний байт выдается в
; приемник.
inc iy ;Туда же выдается его
LD A.L : коэффициент повтора
LD (IY+O). А ;из регистра L.
PUSH IY ;Аналогично операции LD HL.IY,
FOP HL ; которой нет в системе команд
; Z-eo.
LD DE. STORE
LD (STORE).HL ;Изменили программную переменную
.STORE, чтобы подготовить приемник
:для нового шаблона.
AND А ;Сброс Флага переноса для того.
; чтобы он не влиял на следующую
; операцию SBC, т. к. операции SUB
;для регистровых пар в системе
; команд Z-80 нет.
SBC HL.DE ;Опеределили длину сконпрессиро-
;ванного шаблона.
LD IY. DE
LD (IY+O).l ; Сохранили длину шаблона вместе
LD (IY+l).H ;c самим сжатым шаблоном.
POP IY :Восстановление ранее сохраненных
;регистров перед окончательным
POP IX ; выходом из процедуры.
RET
2. 7. г. Буферизация экрана.
декомпрессия шаблонов может производиться как непосредст-
венно на экран, так и в заранее организованный для этой цели
буфер. Возможна и двойная буферизация, когда каждый шаблон сна-
чала декомпрессируется в буфер шаблонов, а потом оттуда впеча-
тывается в буферный экран, который в свою очередь потом копиру-
ется в экранную область памяти.
.Вроде бы при таком порядке действий значительно замедлится
быстродействие программы, но это не совсем так. программисту
ведь не нужна скорость ради скорости. Ему нужна скорость работы
только для того, чтобы освежение (перестроение) экрана происхо-
дило бы как можно более быстро, а самые быстрые результаты по-
казывает применение копирования экрана с помощью команды блоч-
ной переброски байтов LDIR (справедливости ради надо отметить,
что есть и еше более быстрые способы переброски больших блоков
данных и об этом мы писали на страницах нашего "Фирменного"
издания "ZX-РЕВЮ").
LD HL. BEGIN ; начало буферного экрана.
LD DE. ЧОООН : начало экранной области.
LD ВС. 1В00Н ; Длина дисплейного файла вместе
с цветовыми атрибутами.
LDIR ;Переброска.
Поэтому заполнение буферного экрана можно производить в тот
момент, когда программа находится в состоянии ожидания действий
пользователя, а это. кстати, основное состояние для любой про-
граммы. То ли пользователь читает какое-то сообщение, то ли
думает, куда бы ему пойти дальше, а в это время незанетно для
него идет "печать" в невидимый буферный экран.
"Печать" в буферный экран может производиться теми же
самыми процедурами, которыми мы печатаем в основной экран с
минимальными доработками. Напомним. как связаны адрес в
экранной памяти с координатами позиции печати:
А: координаты заданы в знакоместах.
как видите, местоположение экранного Файла в оперативной
памяти определяют три старших бита, в которых стоит число о 1
О. Устанавливаются эти биты командой OR 40Н. ниже приведен
фрагмент процедуры (см. раздел 1.3). которая это делает
LD А. Е
AND 18Н
OR 40Н
Если эту раскладку изменить, то соответственно Вы
получите новые адреса, в которые сможете "печатать" • свои
шаблоны, как на экран.
0 10 - адрес 16384 - OR 40Н
Oil - адрес 24576 - OR 60H
10 0 - адрес 32768 - OR 80H
10 1 - адрес 40960 - OR AOH
110 - адрес 49152 - OR СОН
111 - адрес 57344 - OR EOH
В: Координаты заданы в пикселах
Здесь точно так же три старших бита, имеюшие раскладку
010. определяют адрес 16384. Но устанавливаются они не так
просто, как это было в предыдущем случае. Ниже мы привели
Фрагмент процедуры из раздела 1. 3, в котором выполняется эта
установка.
LD Е.А Этими тремя командами
and а - о-выставляется конфигу-
RRA раиия 010.
SCF - 1- Ее можно изменить и
RRA сделать другую конФигу-
AND А - О- рацию.
rra Там. где вам нужен ноль.
xor Е нужно поставить команду
and 0F8H and а. а там. где нужна
XOR Е единица, нужно поставить
ld Н.А команду SCF
Таким образом, если Вы хотите, например, чтобы буферный
экран располагался начиная с адреса 57344. Вам надо заменить
эти команды на:
SCF - 1
RRA
SCF - 1
RRA
SCF - 1
RRA
Примечание, если координаты заданы в пикселах, то мы копи-
руем шаблон на экран с помошью процедуры PLOT, расположенной в
ПЗУ по адресу 22Е5Н = 8933 DEd (см. г. 2. 2). но если мы хотин
"печатать4 не на основной экран, а в "теневой", то пользоваться
этой процедурой нельзя, ведь надо внести изменения, а в ПЗУ их
внести нельзя. Тогда сами напишите свою процедуру, эквивалент-
ную PLOT (мы рассмотрели ее в книге "Элементарная графика"), и
внесите необходимые изменения.
2. 7. з. Методика декомпрессии.
Для простоты изложения мы предположим, что декомпрессия
производится в буфер, откуда шаблон может быть напечатан с по-
мошью рассмотренных выше процедур как в дисплейный Файл, так и
в буферный экран, мы также не будем останавливаться на простои
рассмотренной выше проблеме поиска шаблона по его номеру и сра-
зу примем, что регистровая пара DE указывает на начало компрес-
сированного шаблона, а в регистровой паре HL устанавливаем ад-
рес буфера, в который происходит декомпрессия.
BUFFER DEFW ОООО
STORE DEFW 0000
LD DE. STORE ;Адрес начала скомпрессированного
; шаблона.
LD L. (DE) ;Младший байт длины шаблона
INC DE ; Переход к старшему байту длины.
LD Н,(DE) .Старший байт длины шаблона.
DEC DE ; Вернулись к началу шаблона.
ADD HL.DE ;И определили адрес его конца.
PUSH HL ;сохранили на стеке адрес конца
;компрессированного шаблона.
INC DE ;Пропуск двух байтов, хранящих
inc DE :длину шаблона.
LD HL. BUFFER ;Адрес буфера-приемника.
again LD a.(DE) ; Приняли байт шаблона.
PUSH AF ;запомнили его на стеке.
INC DE ;Переход к новому байту.
LD a.(DE) ;Приняли очередной байт
; ото коэффициент повтора)
inc de ;переход к новому байту.
ld В. А ; В регистре В организуется
;счетчик повторов.
POP AF ; Восстановили байт шаблона.
LOOP LD (HL). А ;И поместили его в буфер.
INC HL ;следующий байт буфера.
DJNZ LOOP ; Повторяем цикл от LOOP столько
;раз. каков коэффициент повтора.
POP ВС ; Восстановили адрес конца шаблона.
LD A. D I
CP В Проверка на конец шаблона.
JR NZ.PASS
LD А. Е
CP С
JR NZ. PASS
RET Если конец, то выход.
PASS PUSH ВС ;Если не конец, то опять запомнили
;адрес конца шаблона на стеке.
JR AGAIN ; И повторяем процесс декомпрессии.