3Bit #01
03 января 2005

Программинг - процедуры печати текста шрифтами 8х8, 6х8, 5х8, 4х8 точек.

    Всё о печати символов...

(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        00111100
     #C002        01000010
     #C003        01000010
     #C004        01111110
     #C005        01000010
     #C006        01000010
     #C007        00000000

  Не трудно  подсчитать, что весь фонт за-
нимает в памяти 2048 байт.
  Наряду  с  обычными  линейными шрифтами,
существуют т.н. экранные  шрифты. Там тоже
каждый символ состоит из восьми байт, раз-
ница  же  заключается в порядке нахождения
данных  восьми  байт символа в блоке шриф-
тов  (Ух, бля, и  сказал ;). Например, всё
та же буква "А" будет храниться вот так:

      adr:          bin:
     #C000        00000000
     #C100        00111100
     #C200        01000010
     #C300        01000010
     #C400        01111110
     #C500        01000010
     #C600        01000010
     #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        01000100
     #C200        10101010
     #C300        10101010
     #C400        11101110
     #C500        10101010
     #C600        10101010
     #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
──────────────────────────────────────────




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Реклама - Реклама и объявления ...
Пользователям - Как распечатывать статьи из журналов на Скорпионе.
История - "Спектрум: новейшая история". Рассказывает Олег Малахов - Stever.

В этот день...   12 ноября