Из журнала 3bit#1, Украина, Харьковская область, 04.01.2005 Всё о печати символов... (C)Cooper/RSM/P7S ------------------------------------------ Сегодня редкая программа, особенно сис- темнная, обходится без этого - без печати символов. На Спектруме существует 4-ре стандарта шрифтов. Они разнятся между собой шириной одного символа. Форматы эти 8х8, 6х8, 5х8, 4х8 точек. Следовательно, первым форматом мы можем поместить в одну строку на экране 32 символа, вторым - 42 символа, третьим - 51 символ, а четвёртым - 64 символа. Мат- рица 5х8 является наименее распространён- ной среди всех других. Что же представляет из себя блок шрифта? Самый обыкновенный шрифт состоит из 256 символов, а точнее - ввиде их образов. Один символ, вне зависимости от размера матрицы, задается 8-ю байтами. Например, вот так хранится в символьном наборе (да- лее - фонт) буква "А": adr: bin: #C000 00000000 #C001 00 1111 00 #C002 0 1 0000 1 0 #C003 0 1 0000 1 0 #C004 0 111111 0 #C005 0 1 0000 1 0 #C006 0 1 0000 1 0 #C007 00000000 Не трудно подсчитать, что весь фонт за- нимает в памяти 2048 байт. Наряду с обычными линейными шрифтами, существуют т.н. экранные шрифты. Там тоже каждый символ состоит из восьми байт, раз- ница же заключается в порядке нахождения данных восьми байт символа в блоке шриф- тов (Ух, бля, и сказал ;). Например, всё та же буква "А" будет храниться вот так: adr: bin: #C000 00000000 #C100 00 1111 00 #C200 0 1 0000 1 0 #C300 0 1 0000 1 0 #C400 0 111111 0 #C500 0 1 0000 1 0 #C600 0 1 0000 1 0 #C700 00000000 Обратите внимания на адреса залегания байтов в памяти. Зачем это надо я расскажу ниже, когда мы эти символы будем печатать на экран. Значит так, с форматом шрифтов разобра- лись. Ещё раз повторяю: всё выше сказанное относится к стандартным фонтам, т.к. суще- ствуют нестандартные шрифты (6х7, пакован- ные, шрифты для пропорциональной печати и прочие). Теперь же, мы будем наши буковки (или чё там у нас ;) выводить на экран. Для этого нам понадобится процедура, ко- торая б пересчитывала заданные нами коор- динаты в соответствующий адрес в экранной области. Тоесть, вот эта... ;=========координаты -> scr adr======== ;in: D - Y координата, E - X координата ;out:DE - screen adress LD A,D AND 7 RRCA RRCA RRCA OR E LD E,A LD A,D AND 24 OR 64 LD D,A Не будем вдаваться в подробности, мол, что, где и как работает, т.к. это общепри- нятая процедура и используется везде. Теперь рассмотрим ньюансы при печати шри- фтов с разными матрицами... Печать символа 8х8 Символы с такой матрицей выводить проще всего. Допустим, в регистре A у нас храни- тся код символа, а в DE - его координаты на экране. Тогда процедура, печатающая си- мвол 8х8 точек, будет иметь вид: ;=====печать символа 8х8 с цветом===== ;in: DE - координаты, A - код символа Pr_Sym LD L,A LD H,0 ADD HL,HL ;умножаем код символа ADD HL,HL ;на восемь... ADD HL,HL LD BC,font ;...и складываем с ADD HL,BC ;адресом начала фонта LD A,D ;знакомая нам уже AND 7 ;процедурка ;) RRCA RRCA RRCA OR E LD E,A LD A,D AND 24 OR 64 LD D,A LD B,8 PRINT LD A,(HL) ;берем байт из фонта LD (DE),A ;и кладем в экран INC HL ;делаем приращение INC D DJNZ PRINT ;переходим по циклу RET ;и возвращаемся... Скорость работы данной процедуры доволь- но-таки малая. Если тебя она, т. е. ско- рость, не устраивает, то пора вернуться к нашим экранным шрифтам. Что же мы тогда имеем? Обратите внимание на конструкцию: LD L,A LD H,0 ADD HL,HL ADD HL,HL ADD HL,HL LD BC,FONT ADD HL,BC В данном фрагменте код символа умножает- ся на восемь и складывается с адресом на- шего шрифта. Это, вообще-то, занимет неко- торую часть процессорного времени. Если уж быть точным, то умножение тратит 33 такта на символ. Вроде чепуха, но при печати, например, целого экрана, этот мизер вылье- тся в изрядное количество тактов. Ввиду особенностей построения экранных шрифтов, для вычисления адреса символа не нужно делать умножение. Тоесть, теперь мы экономим эти 33 такта, да и в цикле печати на экран вместо INC HL, нужно делать INC H, что экономит еще 16 тактов. "А можно ли еще быстрее",- спросит на- чинающий кодер. Конечно можно. Вот смотри- те: первое, что можно сделать, особо не напрягаясь, так это "развернуть цикл". То- есть, теперь нам не приходится грузить в регистр B "восемь" (экономим 7 тактов) и, соответственно, не надо делать DJNZ, что тоже экономит изрядное количество тактов. Но учтите, что участок кода, перебрасываю- ший байты шрифта в экран надо повторить 8 раз, а это приводит к увеличению размера процедуры. За все надо платить :( Да, и не забудьте, при переброске последнего байта на экран, убрать лишние команды INC D и INC H . Зачем тратить на них время? Для особо ленивых привожу текст ускорен- ной процедуры. А вот и он ;) ;=====печать символа 8х8 (fast) ===== ;in: DE - координаты, A - код символа Pr_Sym LD L,A ;в HL - код симво- LD H,0 ;ла, который мы LD BC,font ;складываем с ADD HL,BC ;адресом начала фонта LD A,D ;знакомая нам уже AND 7 ;процедурка ;) RRCA RRCA RRCA OR E LD E,A LD A,D AND 24 OR 64 LD D,A DUP 7 ;директивы ALASM!!! LD A,(HL) ;берем байт из фонта LD (DE),A ;и кладем в экран INC H ;приращение fnt adr INC D ;приращение scr adr EDUP ;и так 8 раз LD A,(HL) LD (DE),A RET ;возвращаемся... Печать символов 4х8 Для печати символов данного размера удо- бнее всего использовать экранный шрифт, где каждый символ продублирован в левой и правой частях. Что-то типа этого: adr: bin: #C000 00000000 #C100 0 1 000 1 00 #C200 1 0 1 0 1 0 1 0 #C300 1 0 1 0 1 0 1 0 #C400 111 0 111 0 #C500 1 0 1 0 1 0 1 0 #C600 1 0 1 0 1 0 1 0 #C700 00000000 Зачем это надо - увидите далее, по ходу статьи. Чем же таким кардинальным отличается пе- чать символов 4х8 от печати символов 8х8? Одно из различий заключается в том, что теперь по X-координате мы можем напечатать целых 64 символа, а следовательно её, т.е. координату, можно задавать от 0 до 63. Далее, нам нужно перевести данные коор- динаты в приемлемый для нас вид, ведь на экране всего 32 знакоместа. Вобщем, не бу- ду здесь страдать херней и этим же заби- вать текст. Короче, Склифосовский!!! Берем координату X, сдвигаем ее командой RR E (обычно Х-овая координата "сидит" именно здесь). Тогда мы получим привычные для 32-символьной печати координаты, а флаг переноса будет указывать какую из по- ловинок знакоместа печатать. Привожу для примера простенькую, но в то же время, вполне работоспособную процеду- ру, печатающую символами данного размера. ;=========================== ;Драйвер печати символов 4х8 ;print A at (D,E) Print4 LD L,A LD H,0 LD BC,Font4 ADD HL,BC RR E JP C,RIGHT CALL Posit LD B,8 LEFT LD A,(HL) ;печать символа в левой части AND %11110000 LD C,A LD A,(DE) OR C LD (DE),A INC D INC H DJNZ LEFT RET RIGHT CALL Posit ;печать символа в правой части LD B,8 RIGHT1 LD A,(HL) AND %00001111 LD C,A LD A,(DE) OR C LD (DE),A INC H INC D DJNZ RIGHT1 RET Как видите - ничего сложного! Печать символов 6х8 А здесь прийдется повозиться, т.к. это наиболее сложная для печати символьная ма- трица. Сразу предупреждаю, что здесь будет опи- сан лишь принцип печати таким шрифтом, не претендующий на что-то особенное, ввиду не самой быстрой скорости печати. Для того, чтобы научиться быстро печатать такими шрифтами советую вам обратиться к другим журналам и газетам, где подробно освещены данные вопросы. Приведу сразу исходник, а потом прокоме- нтируем всё это. ;=========================== ;Драйвер печати символов 6х8 ;print A at (D,E) Print68 EX DE,HL PUSH HL PUSH DE PUSH BC EX DE,HL ;ищем адрес символа LD L,A LD H,0 LD BC,Font6 ADD HL,BC EX DE,HL ;DE-char image GetMasks LD A,L LD B,A SRL A SRL A LD C,A ADC A,C ADD A,C LD L,A ;процедура coords->scr adres= LD A,H AND #07 RRCA RRCA RRCA ADD A,L LD L,A LD A,H AND #18 OR #40 LD H,A ;HL-screen addr PUSH HL ;в зависимости от X координаты LD A,B ;берём нужную маску для печати AND #03 ADD A,A LD L,A LD H,#00 LD BC,Masks ADD HL,BC LD C,(HL) INC HL LD B,(HL) ;BC-mask POP HL EXX LD B,8 ;BC=mask PrtA1 EXX LD A,(DE) BIT 7,B JR NZ,PrtA2 RRCA RRCA BIT 0,C JR NZ,PrtA2 RRCA RRCA BIT 3,B JR NZ,PrtA2 RRCA RRCA PrtA2 EXX LD C,A EXX BIT 0,C JR NZ,PrtA3 LD A,B CPL AND (HL) LD (HL),A EXX LD A,C EXX AND B OR (HL) LD (HL),A BIT 7,B JR NZ,PrtA4 PrtA3 INC L LD A,C CPL AND (HL) LD (HL),A EXX LD A,C EXX AND C OR (HL) LD (HL),A DEC L PrtA4 INC H INC D EXX DJNZ PrtA1 POP BC POP DE POP HL RET Masks DEFW #FC00 ;маска печати для символов 6х8 DEFW #03F0 DEFW #0FC0 DEFW #003F При печати такими шрифтами нам уже при- ходится пользоваться такими вещами, как маска (что это такое, я думаю, объяснять не надо, т.к. обычно все программеры начи- нают свой путь с печати спрайтов. А там и до маски недалеко ;) Вообщем, данная про- цедура печатает сразу по два знакоместа. Это нужно по той причине, что ширина сим- вола ну никак не кратна знакоместу и полу- чается, что некоторые символы необходимо печатать на стыке двух знакомест. Интерес же заключается в том, что 4-ре символа по ширине занимают ровно три знакоместа. Поэ- тому, как не трудно догадаться, масок все- го четыре. Ведь после каждого четвёртого символа мы начинаем печать с начала знако- места и т.д. При старте, в зависимости от координаты X, выбирается необходимая маска и ложится на экран, только потом поверх накладывает- ся символ. Думаю, что принцип понятен ;) Можно печатать стринги (сообщения) пор- циями, по 4-ре символа в каждой, т.е. кра- тно знакоместам. Тем самым повышается ско- рость печати. Но надо использовать уже другую процедуру ;) Печать символов в цвете Для этого нам надо после вычисления ад- реса в экране использовать данную процеду- рку, которая пересчитывает адрес в экран- ной области в соответствующий адрес в об- ласти аттрибутов. ;=========scr adr -> attr adr======== ;in: DE - screen adress ;out:DE - attr adress LD A,D RRCA RRCA RRCA AND 3 OR #58 LD D,A Для символов 8х8 и 4х8 я думаю всё и так понятно, а вот для печати 6х8 надо помоз- говать с проверкой на то, сколько знакоме- ст надо окрашивать - одно или два. Но это я оставлю вам на самостоятельную проработ- ку. Не всё же жевать и в рот ложить ;) На- до и самим немного думать. А то будем мы здесь все с атрофированными как у ПЦ'шных геймеров мозгами ;) Печать стрингов Даю напоследок простенькую процедурку для печати сообщений. Да, токен установки координат может быть любым - это уже ваше дело. Можно добавить сюда и токен установ- ки цвета: 16, код цвета. А можно как и в ACEdit' е ;) ;================================== ; -=Процедура печати стрингов=- ;вх: DE - координаты ; HL - адрес строки текста ;поддерживаются токены: ;0 - конец текста ;17,X,Y - установка координат печати ;================================== Pr_Str LD A,(HL) ;взять код символа AND A ;проверить на ноль RET Z ;совпало - выйти CP 17 ;проверка на токен JP NZ,Pr_Cont INC HL ;установка новых координат LD E,(HL) INC HL LD D,(HL) INC HL JP Pr_Str Pr_Cont PUSH HL PUSH DE CALL Print8 ;нужная Вам процедура печати POP DE POP HL INC E INC HL JP Pr_Str ------------------------------------------