Абзац
:: Поиск
:: ПоддерЖка ПрОекта
Webmoney:
  • Z610389805629
  • R427996570517
  • E023541002978
  • :: №4 (17.03.2001) ПрОсмотрОв: 3223

    Автор: Joker.

    Рубрика: Читатель читателю.

    Номер: №4 (17.03.2001).



    Быстрая процедура печати

    Здравствуйте, уважаемые читатели. Вот и я написал СВОЙ абзац. Не знаю как вы, а я вот соскучился по статьям посвящённым не глубоким абстрактным размышлениям (хотя они нужны и полезны), а самым простым вещам - coding’у, графике, музыке, железу, demo и gamemaking’у и всему прочему, что для меня, например, и составляет предмет творчества на Speccy. Посему статья эта будет посвящена одной из таких вещей -программированию.

    Хочу предложить вам несколько идей по поводу печати строк шестипиксельным font’ом. Я знаю, что вам такая печать жизненно необходима, хотя бы потому что сейчас каждый уважающий себя синклерист выпускает свой компьютерный журнал, газету, боевой листок и так далее (я и сам выпускаю, чего уж там... :-)). Кроме того, я надеюсь, что данная публикация подтолкнет других к написанию статей в «Абзац» на тему coding’а и т.п. (смотрим выше (даешь, понимаешь, гасилку как...).

    Итак, быстрая печать. Сразу скажу, что речь далее будет вестись не об универсальных процедурах, а о печати именно строк (не отдельных символов), оптимизированной по скорости (в ущерб, кстати, памяти).

    Для ускорения вывода создадим к основному шрифту ещё 3, символы в которых будут располагаться, соответственно, со смещением в 2, 4 и 6 пикселей от левого края. Чтобы при печати строки не тратить время на вычисление адреса нужного символа, лучше создавать font’ы таким образом, чтобы изображение первого символа лежало в байтах с адресами: font, font+#100, font+#200, ... , font+#700, изображение 2-го в байтах с адресами: font+#001, font+#101, font+#201, ... , font+#701, где font - адрес шрифта в памяти, кратный 256. Таким образом для вычисления адреса символа нужно будет занести в старший регистр старший байт адреса фонта, а в младший поместить код символа. Для пояснения всего вышесказанного приведу пример подпрограммы, формирующей соответствующие шрифты:


    INS_FON LD DE,SH60         ; формируем шрифт
            CALL INSF_1        ; со смещением 0
            LD A,#0F,(IFF_1),A
            LD (IFF_1+1),A
            LD DE,SH63         ; -- / --
            CALL INSF_1        ; со смещением 2
            LD DE,SH61         ; -- / --
            CALL INSF_2        ; со смещением 6
            LD A,0,(IFF_2),A
            LD DE,SH62         ; -- / --
            CALL INSF_2        ; со смещением 4
            RET
    
    INSF_2  LD IX,font
            LD E,#20           ; код 1го символа (пробел)
            LD C,224           ; считаем, что всего в
                               ; шрифте 224 символа
    SF2_1   PUSH DE
            LD B,4
    SF2_3   CALL SF2_2
            LD A,L,(DE),A:INC D; зачем сделано
            LD A,H,(DE),A:INC D; именно так
            CALL SF2_2         ; можно прочи-
            LD A,H,(DE),A:INC D; тать ниже
            LD A,L,(DE),A:INC D;
            DJNZ SF2_3
    SF2_3B  POP DE
            INC E,IX
            DEC C:JR NZ,SF2_1
            RET
    SF2_2   LD H,(IX+0),L,0:INC IX
    .2      AND A:RL H,L
    IFF_2   RET
    .2      AND A:RL H,L
            RET
    
    INSF_1  LD HL,font
            LD E,#20,C,224
    SF1_1   PUSH DE
            LD B,8
    SF1_2   LD A,(HL):INC HL
    IFF_1   NOP:NOP
            LD (DE),A:INC D
            DJNZ SF1_2
            POP DE
            INC E,HL
            DEC C:JR NZ,SF1_1
            RET

    Здесь font - адрес исходного обычного шрифта; SH60, SH61, SH62, SH63 - адреса формируемых шрифтов, должны быть кратны 256. В INSF_2 формируются шрифты по размеру в два раза больше, чем в INSF_1 из-за того, что при смещении изображения символа на 4 и 6 пикселей вправо оно выходит за границы одного байта. Причём, в INSF_2 шрифт формируется таким образом, что 2-я, 4-я, 6-я и 8-я линии изображения каждого символа хранятся в обратном порядке, т.е. сначала идёт правый байт, потом левый (чтобы понять, что я тут хотел сказать лучше посмотреть на саму эту процедуру и всё сразу станет ясно). В таком виде будет удобней выводить строку символов.

    Теперь непосредственно о самой печати. Основная идея: при печати шестипиксельным шрифтом рассматриваются четвёрки символов, которые очень хорошо вписываются по ширине в три байта. Поэтому нужно выводить символы не отдельно друг от друга, а одновременно печатать на экран сразу всю четвёрку. В этом случае исчезает много ненужных команд, типа LD A,(DE), LD (DE),A, которые нужны при последовательном выводе (так, например, для вывода 2-го символа четвёрки нужно взять с экрана изображение уже напечатанного 1-го, совместить его со 2-м, положить обратно на экран. То же самое с 3-м и 4-м). Для вывода одновременно всей четвёрки нам нужно иметь следующие адреса:


    адрес текста - допустим он в DE';
    адрес на экране, куда выводится
    строка - DE;
    адрес 1-го символа - BC;
    адрес 2-го символа - HL;
    адрес 3-го символа - HL';
    адрес 4-го символа - BC';


    Сделаем  набросок процедуры вывода всей строки:


    LIN_1   LD B,SH60[        ; заносим старшие
            LD H,SH61[        ; байты адресов в
            EXX
            LD H,SH62[        ; соответствующие
            LD B,SH63[        ; регистры
            LD A,(DE):INC DE  ; код 1го символа
                              ; четвёрки
            ...
    
    ; здесь следовало бы поставить проверку
    ; на различные управляющие коды,
    ; как то: конец строки, цвет и т.д.
    ; Думаю это каждый сможет сделать сам
    
            EXX:LD C,A:EXX    ; в BC уже есть
                              ; адрес
            LD A,(DE):INC DE  ; 2-ой символ
            ...
            EXX:LD L,A:EXX    ; 2-ой адрес
            LD A,(DE):INC DE  ; 3-й
            ...
            LD L,A            ; и так далее
            LD A,(DE):INC DE
            ...
            LD C,A
    
            EXX
    
    ; теперь непосредственно сам вывод
    
            LD A,(BC):INC B   ; выводим 1-ю
            OR (HL):INC H     ; (3-ю, 5-ю, 7-ю)
            LD (DE),A:INC E   ; строчку слева
            LD A,(HL):INC H   ; направо, т.е.
            EXX               ; как обычно
            OR (HL):INC H     ;
            EXX               ;
            LD (DE),A:INC E   ;
            EXX               ;
            LD A,(BC):INC B   ;
            OR (HL):INC H     ;
            EXX:LD (DE),A:
            INC D;
    
            EXX               ;
            LD A,(BC):INC B   ; выводим 2ую
            OR (HL):INC H     ; (4-ю, 6-ю, 8-ю)
            EXX               ; строку справа
            LD (DE),A:DEC E   ; налево - для
            EXX               ; этого в процедуре
            LD A,(HL):INC H   ; INSF_2 мы и сде-
            EXX               ; лали небольшой
            OR (HL):INC H     ; изврат в формате
            LD (DE),A:DEC E   ; шрифтов
            LD A,(BC):INC B   ;
            OR (HL):INC H     ;
            LD (DE),A:INC D   ;
            ...
    ; повторяем эти два блока ещё 3 раза
    ; для вывода всех восьми строк
            LD A,D:SUB 8:LD D,A
    .3      INC E;
    ; переходим на три байта вправо и
    ; восстанавливаем значение регистра D
            ...
    ; здесь можно было бы поставить проверку
    ; на то, выходит ли строчка за экран и
    ; т.д.
            JP LIN_1

    Про вывод цветов говорить, наверное, не стоит - ничего сложного в нём нет, к тому же особого влияния на скорость работы всей программы этот вывод не оказывает. В программе не показано ещё много мелочей - цель статьи изложить лишь идею, которую каждый может воплотить по-своему. Средняя скорость работы viewer’а, написанного с использованием данного алгоритма - 5-6 фреймов на обновление экрана размером 22*40 символов.


    От редакции: В листинге присутствуют особенности ассемблера Storm. Например: .3 INC E, что при компиляции дает 3 команды INC E.

    © 2004-2013 Perspective group