Deja Vu #05
31 мая 1998

CODING - Кодить хочу - процедуры вывода спрайтов без атрибутов, быстрая и универсальная процедура вывода спрайтов, процедура умножения и вычисления квадратного корня.

SoundTrack: DEVOUR OF BRAIN BY DX-69 1998 
__________________________________________


(C) Card!nal/PGC/BD
__________________________________________


   Привет,дорогие читатели нашего журнала!
Даниил  тут попросил  меня написать статью
по coding'у, и я вот сижу за текстовым ре-
дактором. Эта статья не имеет определенной
цели, просто я расскажу об оптимизации  и,
вообще, что у меня  накопилось  с  выпуска
четвертого номера Deja Vu.


   Для  начала поговорим о выводе спрайтов
без атрибутов. Вот стандартная процедура:

        LD HL,adr    ;адрес спрайта
        LD DE,#4000  ;адрес в экране
        LD B,192     ;высота в пикселях
        LD C,32      ;ширина в знакоместах
LOOP2   PUSH DE
        PUSH BC
        LD B,0
        LDIR
        POP BC
        POP DE
        INC D
        LD A,D
        AND 7
        JP NZ,METKA1
        LD A,E
        ADD A,32
        LD E,A
        JP C,METKA1
        LD A,D
        SUB 8
        LD D,A
METKA1  DJNZ LOOP2
        RET


   А  теперь  давайте  посчитаем,  сколько
тактов  она работает. Не углубляясь в под-
робности,  как  я это посчитал, скажу, что
она работает около 146000 тактов при выво-
де  спрайта  размером  с  экран. В среднем
тратится 23.7 тактов за байт. Вообщем, это
неплохая процедура вывода статических кар-
тинок,  ну, а если вам нужна быстрая, УНИ-
ВЕРСАЛЬНАЯ  процедура, тогда смотрите ниж-
ний  листинг. Под  словом  универсальная я
подразумевал, что можно  произвольно зада-
вать  высоту, ширину спрайта и его коорди-
наты на экране.

        CALL DECRUN ;эта программа делает
                    ;таблицу адресов
                    ;экрана

        LD HL,adr  ;адрес спрайта
        LD D,3     ;коорд. X в знакоместах
        LD E,8     ;коорд. Y в пикселях
        LD B,100   ;высота в пикселях
        LD C,20    ;ширина в знакоместах

WIWOD   DI
        LD A,D
        LD (WIW1+1),A
        LD A,C
        ADD A,A
        SUB 64
        NEG
        LD C,A
        LD A,B
        LD B,0
        LD IX,WIW2
        ADD IX,BC
        EX DE,HL
        LD H,B
        ADD HL,HL
        LD BC,BUFER
        ADD HL,BC
        LD (STACK+1),SP
        LD SP,HL
        EX DE,HL
        LD B,A
LOOP1   POP DE
        LD A,E
WIW1    ADD A,0
        LD E,A
        LD C,D
        JP (IX)
WIW2
        DUP 32
        LDI      ;команда LDI повторяется
        EDUP     ;32 раза

        DJNZ LOOP1
STACK   LD SP,0
        EI
        RET


DECRUN  LD HL,BUFER
        LD DE,#4000
        LD B,192
LOOP    LD (HL),E
        INC HL
        LD (HL),D
        INC HL
        INC D
        LD A,D
        AND 7
        JR NZ,METKA
        LD A,E
        ADD A,32
        LD E,A
        JR C,METKA
        LD A,D
        SUB 8
        LD D,A
METKA   DJNZ LOOP
        RET
BUFER   DEFS 384


   Процедура  работает  108076  тактов при
выводе  спрайта  величиной  с экран, что в
1.35  раза  быстрее  предыдущей. В среднем
тратится 17.6 тактов за байт. Подпрограмма
DECRUN запускается только один раз,а даль-
ше можно пользоваться подпрограммой  WIWOD
сколько угодно. Скажу только,что нужно за-
прещать прерывания, так как юзается  стек.
Постарайтесь сами разобраться, как все ра-
ботает. Я только подскажу зачем нужна  ко-
манда LD C,D перед  командой  JP (IX). Как
известно, LDI при работе уменьшает регист-
ровую пару BC, так вот, чтобы не  портился
регистр B, нам нужно постоянно  держать  в
регистре C число больше, чем  максимальная
ширина спрайта,то есть больше 32,а регистр
D всегда содержит число больше 32.

   Ну все, с выводом спрайтов разобрались,
поговорим о повороте спрайта на любой угол
(0  - 360). В четвертом Deja Vu был исход-
ник  Колотова "TURN SPRITES". Честно гово-
ря, я  видел  эту  программку еще раньше и
скажу, что  качество работы программы меня
не  очень-то  обрадовало :-(. Я попробовал
повернуть залитый квадрат 5 на 5 знакомест
на 45 градусов и увидел неприятную картин-
ку, квадрат уже был похож не на квадрат, а
на квадратное решето, и использовать такую
программу  было затруднительно. А все дело
в  алгоритме  поворота и не учета строения
экрана. Я  реализовал несколько другой ал-
горитм  и  результат  просто  потрясающий.
Картинка почти (учитывая низкое разрешение
экрана)  не искажается. Если вы, например,
повернете  залитый  круг радиусом 50 на 45
градусов  вокруг  его  центра, то получите
такой  же  круг. Правда этот алгоритм не я
придумал, а взял его из журнала ZX NEWS 3.
Там  была  статейка о повороте спрайтов, и
была дана программа на бейсике. Программка
эта  работала более часа, поворачивая весь
экран. Аналога  в  кодах этой программы не
было, а  автор  сознался, что не дружит со
встроенным  калькулятором  бейсика. Честно
говоря, я  тоже  не  дружу  со  встроенным
калькулятором, а  потому реализовал данный
алгоритм в кодах без использования кальку-
лятора. Первая версия моей программы рабо-
тала  3.5 минут, поворачивая весь экран не
важно на какой угол. Я решил, что это пол-
ный  SUXX  и чуть-чуть оптимизировал ее. В
итоге получилось около 40 секунд, что при-
мерно  в 5 раз быстрее первоначального ва-
рианта и в 100 раз быстрее чем на бейсике,
и это,заметьте,без потери качества изобра-
жения. Дальше оптимизировать было лень,хо-
тя была перспектива довести время до 10-15
секунд, а то и быстрее, но эту  радость  я
могу предоставить вам, SERZH, ты меня  по-
нял  :-). В приложении найдете исходник  в
формате ALASM 3.8c. Исходник содержит  ко-
ментарии, так что разберетесь. Не смотрите
на убогий код,некогда было его вылизывать.
Началом координат считается  левый  нижний
угол экрана, если я не ошибаюсь. Поворачи-
ваемый спрайт (не дай себе засохнуть!)дол-
жен уже быть на экране. Программа  исполь-
зует приличный объем  памяти ( 6144 + при-
мерно 2кг ) байт для буфера,там увидите...
Чуть не забыл рассказать алгоритм  поворо-
та. Берется точка с координатами  (x0,y0),
поворачивается на угол и получается  коор-
дината (x1,y1), из координаты (x1,y1)  бе-
рется точка (если она есть) и  переносится
в координату (x0,y0), потом берется  след.
(x0,y0) и т.д. Проверки выхода за  пределы
экрана, OF COZZZ, делаются,так что все на-
мана :-).

   Ну что? Поехали дальше! Меня тут  некий
CRANK попросил помочь разобраться в "заум-
ных xor'ках", а посему скажу вот что. Нау-
читься разбираться в xor'ках ты должен сам
(с помощью STS v6.2, например). Постарайся
разобраться, что она  расxorивает, трасси-
руй,  внимательно следи за регистрами, ре-
зидент STS'а переноси, если нужно, в безо-
пасное  место. Простейшая  xor'ка выглядит
так:

        LD HL,adr
        LD BC,lenght
LOOP    LD A,(HL)
        XOR 23
        LD (HL),A
        INC HL
        DEC BC
        LD A,B
        OR C
        JR NZ,LOOP
        RET


   If you have a pC, то можете там набрать
программу в ассемблере или в hiew (если ты
извращенец :-)).

        mov dx,adr
        mov bx,lenght
loop    mov si,dx
        mov al,[si]
        xor al,23
        mov [si],al
        inc dx
        dec bx
        jnz loop
        retn


   Мне, конечно, все  равно где кодить, но
SPECCY, OF COZZZ, RULEZ форева!!!


   С  xor'ками  вроде  разобрались, как на
Спектруме, так  и  на  ПИСИ, поэтому пошли
дальше  :-).  Я  хотел бы еще сказать пару
слов о переключении страничек. Вот, напри-
мер, какую программку я увидел у SERZH'а в
одной  из его рулезных (как всегда) стате-
ек:

        LD BC,#7FFD
        OUT (C),A
        LD (BANK),A
        RET
BANK    DEFB 0


   Или  что-то  в этом роде. Что же мы ви-
дим? Вроде все правильно... Ан  нет! Пред-
ставим ситуацию,что прерывания пришли меж-
ду командами out (c),a и ld (bank),a. Пре-
рывания отработают и вернутся  обратно. Но
при выходе восстановится  старое  значение
BANKи и в итоге цветные квадратики на  эк-
ране, а посему  сохранять  значение  нужно
перед out (c),a.


   Т.к. Deja Vu теперь будет выходить  без
защиты, то я хотел рассказать  о  классном
способе защиты от копирования  придуманном
мной (диск нельзя скопировать даже  на  pC
и Amiga) и даже хотел кинуть  исходники  в
приложение (форматер и читалка формата),но
потом подумал, что слишком жирно  будет! И
отказался от этой  затеи. Хотя, если  меня
хорошо попросят, то может  быть  расскажу.
Теперь поехали дальше.

   Хочу сказать пару  слов  о  игре Черный
ворон, крутая надо сказать игруха. Но  не-
которые уровни просто убийственные (я имею
ввиду  почти непроходимые), а так как я не
геймер и игрушками не увлекаюсь шибко, по-
этому облегчил себе жизнь, вставил парочку
POKES  и  увидел  FINAL CUT! Если обнулить
три  байта с адреса #D5CE в RAM0, то у вас
перестанут  кончаться  деньги. Ну, а номер
текущего  уровня хранится по адресу #79D8.
Например, заносите  туда  номер следующего
уровня, делаете  "повторить  попытку" и вы
уже  на  другом  уровне. Если туда занести
#10, то  увидите FINAL CUT. "Все это прек-
расно",скажете вы - "А как же защита?" Тут
вы  правы, даже теневик не поможет. А поэ-
тому  выкручивайтесь сами, ломайте как хо-
тите. Я не имею морального права учить вас
ломать коммерческие продукты. Скажу  толь-
ко, я потратил три дня, чтобы вставить PO-
KES!

   Далее поговорим об алгоритме умножения.
Простейшая  процедура  умножения на SPECCY
выглядит так: HL = A*E


        LD H,A
        LD L,0
        LD D,L
        LD B,8
LOOP    ADD HL,HL
        JR NC,$+4
        ADD HL,DE
        DJNZ LOOP
        RET


   Не трудно подсчитать количество тактов:
минимум  310, максимум 358 без  учета RET.
Конечно, если развернуть  цикл, мы получим
минимум 206, а максимум 254 такта. А можно
ли  побыстрее? Yes, of cozzz! Но для этого
нужно  вспомнить начальную алгебру. А точ-
нее  формулы сокращенного умножения:

    Квадрат суммы: (a+b)^2=a^2+2ab+b^2
    Квадрат разности: (a-b)^2=a^2-2ab+b^2


   Возьмем  эти формулы на вооружение. Для
того, чтобы  написать процедуру умножения,
нужно  сформировать табличку квадратов чи-
сел  от  0  до  255  включительно. Таблица
квадратов будет основной частью программы.
Адрес таблицы должен быть кратным 256, т.е
младший  байт  = 0. Это  делает  следующая
программка.

SET_TBL LD DE,TABL
        LD H,E
        LD L,E
        LD B,E
        LD C,E
SET_T1  LD A,L
        LD (DE),A
        INC D
        LD A,H
        LD (DE),A
        DEC D
        ADD HL,BC
        INC C
        ADD HL,BC
        INC E
        JR NZ,SET_T1
        RET
TABL    DEFS 512


   А вот и сама процедура умножения. Числа
от  0  до  255 задаются в регистрах L и E.
Ответ в HL.


MULS    LD H,'TABL
        LD C,(HL)
        INC H
        LD B,(HL)
        LD A,L
        ADD A,E
        JP NC,MUL4
        JP M,MUL1
        SUB E
        SUB E
        JP NC,MUL2
        LD A,E
        SUB L
MUL2    LD L,E
        LD D,(HL)
        DEC H
        LD E,(HL)
        LD L,A
        LD A,(HL)
        INC H
        LD H,(HL)
        LD L,A
        SBC HL,BC
        OR A
        SBC HL,DE
        LD A,L
        CPL
        LD L,A
        LD A,H
        CPL
        LD H,A
        INC HL
        SRL H
        RR L
        RET
MUL4    LD L,E
        LD D,(HL)
        DEC H
        LD E,(HL)
        LD L,A
        LD A,(HL)
        INC H
        LD H,(HL)
        LD L,A
        SBC HL,BC
        OR A
        SBC HL,DE
        SRL H
        RR L
        RET
MUL1    LD A,L
        SUB E
        JP NC,MUL3
        LD A,E
        SUB L
MUL3    LD L,E
        LD D,(HL)
        DEC H
        LD E,(HL)
        LD L,A
        LD A,(HL)
        INC H
        LD H,(HL)
        LD L,A
        SBC HL,BC
        OR A
        SBC HL,DE
        SRL H
        RR L
        LD A,L
        CPL
        LD L,A
        LD A,H
        CPL
        LD H,A
        INC HL
        RET


   В  итоге количество тактов минимум 141,
а максимум 207, что, согласитесь, немного.
Этот  алгоритм  был  позаимствован из игры
BATTLE  COMMAND 128. К тому же об этом пи-
салось в электронном журнале "Спектрум Эк-
сперт 1". Однако, там приводилась несколь-
ко иная программа, которая учитывала знаки
при умножении, и было ограничение чисел от
-128 до +127, что не всегда удобно.
   Теперь  давайте  поговорим о вычислении
квадратного корня. В ZX FORMATE 7 была ка-
кая-то  программка  вычисления корня, но я
прямо  скажу, что  не очень. А  все дело в
скорости. Я попробывал вычислить с помощью
той программки корень из 1024. Потрассиро-
вал  STS'ом  и  оказалось, что программа 5
(пять)  раз делает деление, а при вычисле-
нии корня из 65535 делает 10 (десять!) де-
лений. Причем процедура деления выполняет-
ся около 1000 тактов,а то и больше. Я тог-
да немного подумал и написал свою. Ее лис-
тинг  дан  ниже. Моя  программа  выполняет
всего  одно деление, если число попадает в
интервал  от 2 до 16383, и выполняется два
деления, если  число  в  интервале 16384 -
-65535. При числах 0 и 1 деления не выпол-
няются. Программа работает по  модифициро-
ванному мною алгоритму Ньютона. Попробуйте
сами  разобраться, как  все  работает. Дам
подсказку: в таблице находятся так называ-
емые  средние  корни чисел от 2^1 до 2^15.
Вычисляются по формуле:

(sqr(2^n)+sqr(2^(n+1)))/2


SQRT    LD A,H   ;HL = SQR (HL)
        OR L
        RET Z
        LD D,H
        LD E,L
        LD B,15
        ADD HL,HL
        JR C,SQRT2
        DEC B
        ADD HL,HL
        JR C,SQRT2
        DEC B
SQRTL   ADD HL,HL
        JR C,SQRT1
        DJNZ SQRTL
        LD HL,1
        RET
SQRT1   LD HL,TABL
        LD C,B
        LD B,0
        ADD HL,BC
        LD C,(HL)
SQRT_   PUSH BC
        CALL DIV
        POP BC
        ADD HL,BC
        SRL H
        RR L
        RET
SQRT2   PUSH DE
        CALL SQRT1
        POP DE
        LD B,H
        LD C,L
        JR SQRT_


DIV     PUSH BC  ;HL = DE/BC с округлением
        LD A,B   ;ответа
        CPL
        LD B,A
        LD A,C
        CPL
        LD C,A
        INC BC
        LD HL,0
        LD A,E
        ADD A,A
        RL D
DUP 16
        ADC HL,HL
        ADD HL,BC
        JR C,$+4
        SBC HL,BC
        RLA
        RL D
EDUP
        LD E,A
        POP BC
        SRL B
        RR C
        OR A
        SBC HL,BC
        EX DE,HL
        RET C
        INC HL
        RET
TABL    DEFB 1,2,2,3,5,7,10,14,19,27
        DEFB 39,55,77,109,155,219


   Время  выполнения  я  не считал, но оно
составляет, примерно, 1500  - 2500 тактов.
Программу  можно  ускорить, если использо-
вать  более  быструю процедуру деления. Но
можно  вообще  обойтись  без делений, если
использовать  другой алгоритм. У меня есть
на  примете  такой, но пока нет достаточно
свободного времени в нем хорошенько разоб-
раться и написать программу :-(

   На  этом мое повествование заканчивает-
ся. Скажу только, что в листингах  исполь-
зовались директивы ассемблера ALASM.
Так, например:

DUP 16
      тело программы
EDUP
означает, что тело программы ассемблирует-
ся 16 раз.

   Напоследок хочу сообщить, что хочу под-
готовить к 6-ому номеру длинную статью  по
3D-графике на SPECCY. В ней будут рассмот-
рены: формулы поворота точек в пространст-
ве, алгоритм рисования залитого  треуголь-
ника, декомпозиция, алгоритм скрытия неви-
димых граней, алгоритм построения  сложных
невыпуклых об'ектов,алгоритмы заливки гра-
ней в зависимости от расположения источни-
ка света и еще что-нибудь. Естественно бу-
дут приведены примеры на  ассемблере. Было
бы желание и свободное время. На этом пока
все. BYE.



Другие статьи номера:

Аперативчик - О новой оболочке журнала.

Аперативчик - Вступление и авторы.

Тема - DIGITAL звук, как он есть (проигрыватель .wav файлов).

Тема - Проект спасения и развития сцены.

Тема - Устав ассоциации AMAZING SOFT MAKING.

Тема - Теория журналостроения.

Капля припоя - GENERAL SOUND: PLUG & PLAY.

Капля припоя - Профессиональная обработка звука на PC.

SOFTWARE - О новинках из Самары: MAX SOFT SCREEN PACKER v1.4 , МИНЕР, FILE COMMANDER v4.04, SLIDE SHOW,WALKER demo,S-LIGHT BBS, S-TERMINAL v1.0, LOGO.SYS (для PC).

SOFTWARE - Описание проходилка игры "Операция Р.Р."

SOFTWARE - Новинки демосцены: HAPPY NEW 1998 YEAR, BURDENSOME, DREAM, CONDEMED, CONFUSION.

CODING - Процедуры: FULL SCREEN SCROLL UP, Сломанный телевизор.

CODING - Использование стека при разрешенных прерываниях.

CODING - О паковщике MS-PACK.

CODING - Кодить хочу - процедуры вывода спрайтов без атрибутов, быстрая и универсальная процедура вывода спрайтов, процедура умножения и вычисления квадратного корня.

ANOTHER WORLD - Мультимедия - синтез трех стихий.

ANOTHER WORLD - AMIGA vs PC.

Доска почета - Интервью с PROGRESS.

Доска почета - О группе ETERNITY INDUSTRY.

Доска почета - О международном фестивале ART COMP-98.

Доска почета - Опpеделения принятые на демосцене и спектруме.

Доска почета - использование мышки в журналах и другом софте (о криворуких кодерах).

Доска почета - о способе конверсии триколорных картинок для спектрума.

Доска почета - такой ли рулез Amiga? Пц для пцшников, а спектрум для спектрумистов?

Семь и 1/2 - Армейские маразмы.

Семь и 1/2 - Программирование снизу вверх на искосок.

Семь и 1/2 - Инструкция по технике безопасного секса.

Семь и 1/2 - Особенности национального рулеза.

Семь и 1/2 - отчет с тусовки Кемеровских спектрумистов и сохдателей журнала Deja vu.

Проба пера - Приключения Винни Пуха часть 2.

Проба пера - Фэнтази и фантастика.

Реклама - Реклама и объявления ...

Новости - новый журнал AMIGA RULES.


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

Похожие статьи:
Top Ten - лучшая десятка игр от C.Филимонова
Письма - Письмо от FileSof'а: отношение к Минским газетам.
Система - Multicolor Studio Compiler

В этот день...   29 мая