© Иван Рощин, Москва
| ZXNet | : 500:95/462.53 |
| : bestview@mtu-net.ru | |
| WWW | : http://www.ivr.da.ru |
(Adventurer #8,
«Радиолюбитель. Ваш
компьютер» 8/2000)
Дата последнего редактирования: 24.09.2004.
Есть такая версия графического редактора Art Studio (v2.01c, corrected by ROM/SM and FUX/SM), которая может проигрывать музыку во время работы. Т.е. на диске записан сам редактор и сразу же за ним файл «artmusic», содержащий откомпилированную музыку в формате Pro Tracker 2 или Sound Tracker Pro. При запуске редактора этот файл загружается в свободный банк ОЗУ (1 или 6), и в процессе работы происходит вызов плеера по прерываниям. (Оказалось, что имя этого файла не имеет значения, лишь бы он был записан непосредственно за редактором, т.е. за файлом «ART <B>».)
Раньше я пользовался другими версиями Art Studio, у которых были свои
недостатки: то стрелка исчезнет непонятно куда, то на экране появятся цветные
полосы и всё зависнет
Так что с появлением новой версии я перешёл на
неё. Но и тут меня поджидали неприятные особенности (в
Довольно долго я работал с такой версией Art Studio, пока не возникла другая проблема: нужно было нарисовать некоторое изображение по известным координатам его точек. Как, например, отметить на рисунке точку с координатами x=45, y=83? Вот если бы на экране постоянно отображались текущие координаты курсора
И тут я подумал: а что если написать модуль с таким же стартовым адресом (#C000), такими же точками входа (INIT=#C000, PLAY=#C006), как и у откомпилированной музыки, а потом «подсунуть» его редактору, записав вместо файла «artmusic». А этот модуль, в свою очередь, каждый раз, когда к нему производится обращение, будет выводить на экран координаты курсора.
Модуль (известный под именем art_xy) был написан и успешно выводил координаты (а кроме того, следил за бордюром и устанавливал нужные мне начальные значения атрибутов). В конце этой статьи приведён исходный текст его главной части, который пригодится вам при разработке собственных модулей.
Что же мы видим? Оказывается, любую отсутствующую в Art Studio возможность нетрудно реализовать самому, написав для этого специальный модуль. А если написано несколько модулей, то можно загружать их по очереди, не выходя из редактора (для этого, естественно, в каждом модуле должна быть предусмотрена команда «загрузить другой модуль и передать ему управление»).

Создать свой модуль, без сомнения, намного легче, чем написать новый графический редактор «с нуля». Различные модули могут быть написаны разными людьми, независимо друг от друга. А в этом и заключается принцип открытой архитектуры. Наверняка James Hutchby, автор Art Studio, и не предполагал о таких возможностях своего редактора.
Какие функции могут содержаться в дополнительном модуле? Например, быстрый
просмотр записанных на диске картинок без загрузки их в редактор, сохранение и
восстановление конфигурации, использование дополнительной памяти (более
128 КБ) в качестве
В
Теперь я более подробно расскажу о том, как написать собственный модуль для Art Studio. Начну с известных мне адресов, по которым находятся переменные редактора:
ink - 52186 (0-7, 8 - transparent) paper - 52187 (0-7, 8 - transparent) border - 52188 (0-7) bright - 52189 (0 - off, 1 - on, 2 - transparent) flash - 52190 (0 - off, 1 - on, 2 - transparent)
Абсолютные координаты курсора (x 56035, y 56036) дублируются по адресам 64977 и 64978 соответственно. Начало координат расположено в левом верхнем углу экрана.
Так как эти переменные находятся в 0 банке памяти, а модуль загружается в 1 или 6 банк, доступ к ним осуществляется с помощью специальных функций (см. листинг).
Во время первых 50 обращений к модулю (т.е. 1 секунда реального времени после запуска редактора) происходит распаковка редактора и инициализация переменных. Если в модуле предусмотрено изменение задаваемых по умолчанию атрибутов (ink, paper, border) на другие, то эти атрибуты нужно устанавливать заново при каждом из первых 50 обращений. Объяснение тут такое: очевидно, при запуске редактора выполняются команды следующего вида:
LD A,0
LD (52186),A ;ink
LD A,7
LD (52187),A ;paper
LD A,7
LD (52188),A ;border
... ;Происходит прерывание, вызывается модуль, который
;устанавливает нужные ink, paper, border.
CALL CLS ;Очистка экрана
;в соответствии с атрибутами.
Видно, что установка нужных атрибутов должна произойти после того, как редактор установит их значения, но до того, как редактор выполнит очистку экрана. А так как неизвестно, какое по счёту прерывание будет соответствовать этому моменту, приходится выполнять установку атрибутов 50 раз.
Кстати, если при запуске редактора нужно изменить заданные по умолчанию значения атрибутов на transparent, это лучше сделать после первых 50 вызовов модуля иначе во время очистки экрана атрибуты знакомест установятся случайным образом.
ORG #C000
JP INIT ;#C000 - INIT
DS 3
JP PLAY ;#C006 - PLAY
RET ;#C009 - STOP
;Значения ink, paper, border:
COLORS DB 7,0,0
;---------------------------------------
;Процедура INIT - выполняется перед
;началом работы редактора.
INIT DI
;Сохраняем память под резидентом:
CALL SAVE_M
;Переносим резидент N3 и запускаем его.
;В ячейке BANK получаем номер банка,
;куда загружен art_xy:
LD HL,RES3_B
CALL LOAD_R
CALL #6000
;Восстанавливаем ранее сохранённый
;участок памяти под резидентом:
CALL LOAD_M
;Вывод сообщения "загружен модуль..."
;и ожидание нажатия клавиши:
CALL #D000
INIT1 XOR A
IN A,(254)
CPL
AND 31
JR Z,INIT1
EI
RET
;---------------------------------------
;Процедура PLAY - выполняется каждые
;1/50 секунды.
PLAY DI
CALL SAVE_M
...
CALL LOAD_M
EI
RET
;---------------------------------------
;Процедура LOAD_M сохраняет в буфере
;участок памяти под резидентом
;(адрес начала - #6000, длина участка -
;длина самого длинного резидента, в
;данном модуле это резидент N3).
LOAD_M LD HL,RES_BUF
LOAD_R LD DE,#6000
LD BC,RES3_E-RES3_B
LDIR
RET
;---------------------------------------
;Процедура SAVE_M восстанавливает ранее
;запомненный (с помощью LOAD_M) участок
;памяти.
SAVE_M LD HL,#6000
LD DE,RES_BUF
LD BC,RES3_E-RES3_B
LDIR
RET
;---------------------------------------
;Процедура GET_MEM - аналог команды
;LD A,(DE). Нужна для доступа к 0 банку
;памяти.
GET_MEM PUSH HL
PUSH BC
PUSH DE
LD HL,RES1_B
CALL LOAD_R
POP DE
CALL #6000
POP BC
POP HL
RET
;---------------------------------------
;Процедура TO_MEM - аналог команды
;LD (DE),A. Нужна для доступа к 0 банку
;памяти.
TO_MEM PUSH HL
PUSH BC
PUSH DE
LD HL,RES2_B
CALL LOAD_R
POP DE
CALL #6000
POP BC
POP HL
RET
;---------------------------------------
;Резидент N1 - LD A,(DE):
RES1_B LD BC,#7FFD
LD HL,(BANK)
OUT (C),H
LD A,(DE)
OUT (C),L
RET
RES1_E
;---------------------------------------
;Резидент N2 - LD (DE),A:
RES2_B LD BC,#7FFD
LD HL,(BANK)
OUT (C),H
LD (DE),A
OUT (C),L
RET
RES2_E
;--------------------------------------
;Резидент N3 определяет, в какой банк
;(1 или 6) загружен модуль art_xy.
;Запоминает это значение в переменной
;BANK.
RES3_B LD BC,#7FFD
LD A,#11
OUT (C),A
LD A,(PRIZN)
CP "+"
LD A,#11
JR Z,RES3_1
LD A,#16
RES3_1 OUT (C),A
LD (BANK),A
RET
RES3_E
;---------------------------------------
;Буфер для запоминания участка памяти
;под резидентом:
RES_BUF DS RES3_E-RES3_B
PRIZN DB "+"
BANK DW #1000