Scenergy #02
31 декабря 1999

Coding - разбор интро Daingy от Cryss/Razzlers.

              Секреты DAINGY

 Вот,  попросили меня тут написать про мою
интру   DAINGY,   которая,  как  известно,
заняла  третье  место на demoparty CC'999.
Честно  говоря,  я  уже толком и не помню,
как там все устроено, но попытаюсь по ходу
этой   статьи   вспомнить  все  тонкости и
раскрыть   вам  суть  некоторых  процедур.
Сразу   хочу   оговориться,   что   я   не
утверждаю,   что  использованные  в  интре
методы   являются   самыми  крутыми  и  не
подлежащими  дальнейшей оптимизации. Более
того, сейчас некоторые моменты мне кажутся
весьма   неудачно   выполненными,  но  что
сделано,   то   сделано,  тем  более,  что
конечный   результат,   по-моему,   весьма
неплох.     Ну    а    теперь    приступим
непосредственно  к рассмотрению исходников
DAINGY.
 Прежде     всего    необходимо    описать
распределение памяти в порядке возрастания
адресов, итак:
 [line](этот адрес  рассчитывается  исходя
   из  адреса chunks)-процедура построения
   в  теневом  буфере  линии  изображения,
   повернутого на некоторый угол.
 [chunks]-здесь расположены текстуры.
 [sin]-синусоида.
 [#8000]-само изображение, длина=#100,
  высота=#1000, 1 байт=1 pixel.
 [tenbuf]-буфер кадра.

tenbuf   EQU #fa00
chunks   EQU #7600
sin      EQU #7900
line     EQU chunks-(linep2-linep1)*32-1

 Адреса   sin   и   chunks  выбраны  таким
образом,  чтобы  разность  между ними была
равна  #300,  так  как  здесь используется
одна  процедура заливки байтом посредством
LDIR  для  обнуления  участка памяти и для
установления   атрибутов,   если   немного
посидеть   и   поразбираться,   то   можно
понять...
 Традиционно     программа    начинается с
decrunching'а.  Рассмотрим  более подробно
все его этапы.
 Сначала    идет    построение   процедуры
поворота одной линии изображения.

         ORG     #6200
decrun   LD      de,line
         LD      a,32
d1       LD      hl,linep1
         LD      bc,linep2-linep1
         LDIR
         DEC     a
         JR      nz,d1
         LDI;ставим команду RET

 Далее  идет построение chunks по таблице.
Замечу, что они имеют размер 8*4 pixels, и
составлены из пар стандартных чанкoв 4*4.

         LD      b,32
         CALL    raspch
         CALL    raspch
         INC     hl
         DJNZ    $-7

 Подпрограмма  raspch  расположена в конце
текста,  но  для  наглядности  приведу  ее
сейчас:

raspch   XOR     a
         RLD
         LD      c,A
         RLCA
         RLCA
         RLCA
         RLCA
         OR      c
         JR      linep2-2;переход на кусок
                         ;кода
                         ;LD     (de),A
                         ;INC    de
                         ;RET
                         ;тем        самым
                         ;экономится  один
                         ;байт.

 Думаю,  в  пояснениях  этот  фрагмент  не
нуждается,   отмечу   лишь,   что  таблица
содержит  все 16*4=64 байта чанков, но так
как  в  каждом  байте  значимыми  являются
только  4 бита, то она приведена к размеру
64/2=32 байта. Можно было сделать табличку
и  меньше, но данный способ компенсируется
минимизацией процедур распаковки.
 Следующий    кусок    кода   обеспечивает
заполнение  нулями  области  chunks,  коды
которых больше чем #0f.

         EX      de,HL
         XOR     a
         CALL    fill2

 Этого можно было и не делать при условии,
что  память  при  запуске  не  была забита
разным мусором.
 Теперь    пришло    время    сформировать
некоторое подобие синуса:

         LD      l,C;на входе имеем
                    ;следующие значения:
         INC     a  ;C=0
                    ;А=0
                    ;DE=sin+#7f
                    ;H=sin&h-старший байт
                    ;адреса sin
         LD      c,6
msin2b   EX      af,AF'
         LD      a,C
         ADD     a,7
         LD      b,A
         EX      af,AF'
msin2a   LD      (hl),A
         LD      (de),A
         INC     l
         DEC     e
         ADD     a,C
         BIT     6,l
         JR      nz,makstr
         DJNZ    msin2a
         DEC     c
         JR      msin2b

 Этот   способ   придуман   мной   лично и
является   самым   коротким  из  всех  мне
известных.  Попробую  объяснить  его суть.
Как   нетрудно  заметить,  разность  между
текущим и последующим значениями в функции
синуса изменяется от максимума до минимума
при  изменении  аргумента  от  0  до PI/2.
Фактически,  эта  разность  равна значению
первой  производной  функции  sin  (x) при
стремлении разности аргументов к нулю. Так
вот,  если мы будем некоторую переменную в
цикле  увеличивать  на  константу, которую
время  от  времени нужно уменьшать (причем
чем больше константа, тем больше раз мы на
нее увеличиваем переменную), то мы получим
некоторое подобие четверти периода синуса.
Этим и занимается вышеприведенный фрагмент
кода.   В   данном   случае   мы  получаем
полупериод    синусоиды    с    амплитудой
изменяющейся  от  #01  до  #ef  без  учета
знака.
 Дальше    идет    формирование   основной
надписи,  вращение над которой вы и можете
лицезреть  после запуска DAINGY. Здесь все
достаточно   тривиально,   разве  что  для
уменьшения   объема   кода   буквы  строки
расположены   в   формате  (letter-#20)*4.
Используется       стандартный       фонт,
расположенный   по  адресу  #3d00,  литеры
которого   утолщаются   в   горизонтальном
направлении.

makstr   LD      ix,string
         LD      de,#8000
ff1      LD      l,(ix)
         INC     ix
         LD      bc,#3d00
         LD      h,C
         ADD     hl,HL
         ADD     hl,BC
         EX      de,HL
         LD      b,8
ff3      PUSH    bc
         PUSH    hl
         EX      de,HL
         LD      a,(HL)
         RRCA
         OR      (hl)
         EX      de,HL
         INC     de
         LD      b,8
ff2      RLCA
         LD      c,0
         JR      nc,$+4
         LD      c,15
         LD      (hl),C
         INC     h
         LD      (hl),C
         INC     l
         LD      (hl),C
         DEC     h
         LD      (hl),C
         INC     l
         DJNZ    ff2
         POP     hl
         INC     h
         INC     h
         POP     bc
         DJNZ    ff3
         LD      de,#f010
         ADD     hl,DE
         EX      de,HL
         INC     e     ;проверка
         DEC     e     ;на конец
         JR      nz,ff1;строки

 Пришло время установить цвет  BORDER'а  и
ATTRIBUTES в обоих экранах

         OUT     (#fe),a;А=0
         CALL    fill

 Подпрограмма   fill   выглядит  следующим
образом:

fill     LD      a,#55
         CALL    fill1
         LD      a,#57+8
fill1    OUT     (#fd),a
         LD      a,65
         LD      hl,#d800
fill2    LD      d,H
         LD      e,L
         INC     de
         LD      (hl),A
         LD      bc,sin+#7e-chunks-64;
         LDIR    ;BC>=#300 след-но
         RET     ;атрибуты мы установили
                 ;правда  с  небольшим
                 ;избытком...

 На этом процесс подготовки заканчивается,
и  начинается основной цикл, повторяющийся
256 раз, т.к. при достижении этого участка
регистр B содержит 0.

start    PUSH    bc
         CALL    wave;построение очередной
                     ;фазы так называемой
                     ;"бегущей волны"

 Вообще-то  сюда нужно было сразу вставить
текст   этой   подпрограммы,   тем   самым
сэкономив 4 байта, но впопыхах я забыл это
сделать...

ugol     LD      a,(kx+1);координата X
         ADD     a,#97-#f0;в зависимости
                          ;от нее
                          ;рассчитывается
                          ;приращение по
                          ;одной из осей
         LD      e,A
         CALL    takesin  ;dy=1*sin(alpha)
         LD      c,A
         LD      a,E
         RLCA
         RLCA
         AND     #7f
         LD      l,A
         LD      d,(HL)
         LD      a,#f0;попробуйте XOR а
         RLD
         CPL
         LD      (hl),D
         LD      (plus+1),a;устанавливаем
                      ;основной уровень
                      ;интенсивности фона
         LD      a,E
         RLCA
         ADD     a,C;A=beta
         EXX
         CALL    takesin;исходя из этого
                ;рассчитывается
                ;приращение по другой оси
         LD      c,A;   dx=1*cos(beta)

 Этот  участок  кода  формирует траекторию
"полета",    приближения,    возникающие в
результате   того,   что   при  вычислении
приращений   значения  аргументов  alpha и
beta  не  всегда  отличаются  на  #40, и ,
вдобавок  ко  всему, устанавливает текущий
цвет фона.
 После  получения  приращений  в  BC и BC'
осуществляем поворот надписи, с занесением
полученного  результата  в буфер по адресу
tenbuf.

kx       LD      a,#10;координата X
         INC     a
         LD      (kx+1),a;A=X+1
         LD      h,A
         JR      nz,$+7;если X=#100, то
           ;начинаем процесс затемнения
         LD      a,#c6;ADD A,n
         LD      (zatemn),a
         EXX
         LD      de,tenbuf
w2       PUSH    bc
         PUSH    bc
         EXX
         PUSH    hl
         PUSH    bc
         EXX
         PUSH    hl
         CALL    line
         POP     hl
         POP     bc
         ADD     hl,BC
         EXX
         POP     hl
         POP     de
         SBC     hl,DE
         EXX
         POP     bc
         DEC     bc;изменяем одно из
                   ;приращений для
                   ;внесения искажения.
         DEC     bc
         LD      a,D
         OR      a
         JR      nz,w2;если не достигли
                      ;конца буфера, то
                      ;повторяем поворот
                      ;для следующей линии

 Итак,   поворот  мы  осуществили,  теперь
настало   время   создать   некую  иллюзию
трехмерности,   путем   создания   боковых
граней у букв. Делается это весьма просто:
поочередно  мы  смотрим  каждый  столбец в
tenbuf,   как   только  встречается  байт,
отличный  от  нуля, начинаем заполнять все
следующие  байты столбца значением, каждый
раз уменьшающимся на единицу. Делается это
до  тех пор, пока не получим отрицательное
число,  либо  не  достигнем нижней границы
буфера.
 Вот текст этой процедуры:

         LD      c,15
         LD      de,32
         LD      l,D
m3d6     LD      h,tenbuf&h
m3d4     LD      a,(HL)
         LD      b,C
         OR      a
         JR      z,m3d1
m3d2     ADD     hl,DE
         JR      nc,m3d4
         JR      m3d5
m3d3     LD      a,(HL)
         OR      a
         JR      nz,m3d2
m3d1     DEC     b
         JP      m,$+4
         LD      (hl),B
         ADD     hl,DE
         JR      nc,m3d3
m3d5     INC     l
         BIT     5,l
         JR      z,m3d6

 Данный  метод построения имеет один очень
существенный    недостаток:   если   буква
целиком  не  помещается  в  буфере,  то мы
будем   наблюдать  резкий  разрыв  боковых
граней,  уходящих за пределы буфера. Чтобы
сгладить  этот  эффект  я затемняю верхнюю
часть изображения, изменяя яркость от 0 до
максимума начиная от верхней границы.

         LD      hl,tenbuf
         PUSH    hl
         LD      c,15
         LD      b,61
de3a     LD      a,(HL)
         SUB     c
         JR      nc,$+3
         XOR     a
         LD      (hl),A
         INC     hl
         DJNZ    de3a
         DEC     c
         JR      nz,de3a-2

 А  для  того,  чтобы  плавно  появить и в
конце-концов  затемнить  картинку я просто
сдвигаю информацию о чанках.

         LD      hl,chunks
         LD      d,H
         INC     d
swet     LD      a,64
         LD      e,A
         LD      c,64
         LDIR
zatemn   SUB     4
         JR      c,$+5
         LD      (swet+1),a

 Тот   же   эффект   можно  было  получить
непосредственно  при выводе, но тогда бы и
без   того   невысокая   скорость   работы
несколько уменьшилась.
 Но так или иначе все преобразования кадра
выполнены и осталось только его вывести на
экран.  Замечу,  что  я  не  "раскручивал"
для ускорения программу вывода, а выполнял
ее просто циклом.

         HALT
         LD      b,D;в B устанавливаем
                    ;старший байт адреса
                    ;информации о чанках
         LD      a,#55+8
         XOR     10
         LD      ($-3),a
         OUT     (#fd),a
         LD      de,#c000
         POP     hl ;в HL получаем
                    ;адрес tenbuf
ch4      PUSH    de
         LD      a,32
ch1      EX      af,AF'
         LD      a,(HL)
plus     ADD     a,0  ;прибавляя здесь
                      ;некоторое значение
                      ;мы устанавливаем
         CP      16   ;цвет фона и
         JR      c,$+5;получаем яркостные
         CPL          ;разводы на буквах
         AND     15
         RLCA
         RLCA
         LD      c,A
         PUSH    de
         !ASSM   3
         LD      a,(BC);этот фрагмент
         INC     bc    ;кода
         LD      (de),A;повторяется
         INC     d     ;3 раза
         !CONT
         LD      a,(BC)
         LD      (de),A
         POP     de
         INC     e
         INC     hl
         EX      af,AF'
         DEC     a
         JR      nz,ch1;проверка на конец
                       ;линии
         POP     de
         LD      a,D
         ADD     a,4
         LD      d,A
         AND     7
         JR      nz,ch4
         LD      a,E
         ADD     a,32
         LD      e,A
         JR      c,ch2
         LD      a,D
         SUB     8
         LD      d,A
ch2      LD      a,H;проверка на конец
                    ;изображения
         OR      a
         JR      nz,ch4
st1      POP     bc
         DEC     b
         JP      nz,start;проверка
                         ;окончания
                         ;основного
                         ;цикла
         LD      hl,10072;выход
         EXX             ;из
         RET             ;интро

 Далее   идут   различные   подпрограмки и
таблички, вкратце рассмотрим и их.

 Табличное вычисление синуса
takesin  LD      l,A
         LD      h,sin&h
         RES     7,l
         RLCA
         LD      a,(HL)
         LD      b,0
         RET     nc
         NEG
         DEC     b
         RET
на входе : в A-аргумент для синуса
на выходе: в A-младший байт синуса
             B-старший байт синуса

 Данные для надписи.
string   DB      #28,#8c,#c8,#e4
         DB      #cc,#cc,#3c,#c8
         DB      #e8,#b0,#28,#8c
         DB      #8c,#64,#64,#64
Строка "*CRYSS/RZL*CC999"

 Итерация поворота для одного пиксела
linep1   ADD     hl,BC;смещaемся по Y
         LD      a,H
         EXX
         AND     %00010
                  ;используется для
                  ;некоторого
                  ;увеличения картинки
         RRCA     ;в высоту
         ADD     a,#80
         LD      d,A
         ADD     hl,BC;смещаемся по X
         LD      e,H
         LD      a,(DE)
         EXX
         LD      (de),A;занесение пиксела
         INC     de    ;в tenbuf
linep2   RET

 Описание chunks.
         DB      0,0,#80,0,#80,#20,#a0,#20
         DB      #a0,#a0,#a4,#a0,#a4,#a1
         DB      #a5,#a1,#a5,#a5,#e5,#a5
         DB      #e5,#b5,#f5,#b5,#f5,#f5
         DB      #fd,#f5,#fd,#f7,#ff,#ff

raspch   см. выше

fill     см. выше

"Бегущая волна"
wave     LD      hl,#8000;координаты
         PUSH    hl      ;"фронта волны"
         LD      b,16
wave1    LD      a,B
         CP      9       ;проверка на
wave2    JR      c,wave3 ;"пик волны"
         LD      c,A
         LD      a,17
         SUB     c
         INC     l
         JR      $+3
wave3    DEC     l
         XOR     (hl)  ;преобразование
         LD      (hl),A;изображения под
                       ;"фронтом волны"
         INC     h     ;переход к
                       ;следующей линии
         DJNZ    wave1
         POP     hl
         INC     l        ;изменение
         LD     (wave+1),hl;координат
         RET               ;"фронта"

 Ну  вот вроде бы и все, что касается кода
DAINGY.   Возможно   я   и  забыл  описать
кой-какие  тонкости,  но общая идея должна
быть  вам понятна, а это, как мне кажется,
и  есть  основная задача этой статьи. Ведь
для  дальнейшего  развития нашего любимого
SPECCY  мы должны делиться нашими знаниями
и опытом, чтобы облегчить и ускорить выход
нового    качественного    софта,    чтобы
продвигать в свет новые методы кодинга, да
и  вообще,  чтобы  просто повышать уровень
интеллекта.
 И  напоследок, хочется снять завесу тайны
со  слова  "DAINGY".  Если  вы попытаетесь
просто  найти  его  в  словаре,  то  у вас
ничего не выйдет, так как это аббревиатура
двух  английских  слов: dainty и gyration,
что    в    переводе   означает   "изящное
вращение".  А теперь попытайтесь составить
аббревиатуру  из  этих слов, но на русском
языке...  Догадались?  Если  да,  то вы по
достоинству    оцените   наши   старания в
подборе оригинального названия для интры.
 За сим прощаюсь с вами до встречи в наших
новых программах.

                   BYE!
                   
(c) Cryss/Razzlers



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

A.O.S.S. - "Сцена больна" переживания Random'a.

A.O.S.S. - Raver рассуждает о сценовой журналистике.

A.O.S.S. - аналитическая статья о музыкальной сцене от Andy Fer.

A.O.S.S. - легко ли быть органайзером группы?

A.O.S.S. - О журналах (мысли вслух).

A.O.S.S. - о канонах демосцены на примере журнала Deja Vu #9.

A.O.S.S. - Сегодня и Завтра отечественной демосцены.

A.O.S.S. - спектрумовская банерная сеть.

Charts - all time favorites.

Charts - current rules (fall edition 1999).

Charts - indexed.

Charts - voting rules.

Coding - 16-битная процедура быстрого возведения в степень.

Coding - Flying представляет макробиблиотеку: Memory Management Library.

Coding - Texture Mapping - реализация от SaiR00S/EI.

Coding - Texture mapping + Phong shading реализация от Senat/Eternity Industry.

Coding - ZXA library: библиотека, предназначенная для создания и проигрывания анимаций.

Coding - Баг в STS?

Coding - Комментарии к исходникам, опубликованным в Scenergy #1

Coding - о библиотеках в программировании на спектруме.

Coding - Принцип упаковки анимаций в демо JAM.

Coding - процедура быстрого умножения.

Coding - разбор интро Daingy от Cryss/Razzlers.

Demo Party - Cafe'2000: Официальное приглашение

Demo Party - CC999.999 information (eng).

Demo Party - D-Man/EI: отчет о Di:Halt:99.

Demo Party - Hartman: отчет о CC'999.

Demo Party - Maxwell и Mr. John: отчет о CC'999.

Demo Party - Merlin/CC: отчет о CC'999.

Demo Party - Paradox'99 - как это было, но лучше б он mUst dIe!!!

Demo Party - PHAT'9: список посетителей.

Demo Party - POL/PHT: отчет о Doxycon '99.

Demo Party - Random/CC: обьемный отчет о CC'999.

Demo Party - SerzhSoft: сказание о CC'999.

Demo Party - Zlincon 2e3 party: минирепортаж.

Demo Party - информация о предстоящем пати PHAT'0.

Demo Party - информация по демопарти CC999.999.

Demo Party - неофициальные результаты Di:Halt'99 с коментариями Diver'a.

Demo Party - обзор демосцены за 1999 год.

Demo Party - отчет организаторов CAFe'99.

Demo Party - пресс релиз Латвийского демопати PHAT'9.

Demo Party - приглашение на латвийское демопати PHAT'9.

Demo Party - рассказ о поездке Antares в Казань на CAFe'99

Demo Party - результаты CC.999.999

Demo Party - результаты CC999.999.

Demo Party - результаты Chaos Construction 999.

Demo Party - результаты Computer Art Festival 1999.

Demo Party - результаты Doxycon'99.

Demo Party - результаты Millenium Party.

Demo Party - результаты Paradox'2k demoparty.

Demo Party - результаты Латвийского демопати PHAT'9.

Demo Party - результаты Ростовского пати Paradox'99.

Demo Party - репортаж Gasman'a с Forever 2e3.

Demo Party - репортаж с Минского демопати Millennium'2000.

Demo Party - финальные результаты Forever 2E3.

Editorial - вступительное слово от Arty.

Editorial - выступительное слово от Random.

Editorial - загоны Raver'а на тему Сцены.

Groups - анкеты действующих групп: Amaltiya Incoropration Software.

Groups - анкеты действующих групп: Antares.

Groups - анкеты действующих групп: Ascendancy Creative Labs.

Groups - анкеты действующих групп: Crushers.

Groups - анкеты действующих групп: E-mage.

Groups - анкеты действующих групп: Eternity Industry.

Groups - анкеты действующих групп: Excess team.

Groups - анкеты действующих групп: Extreme Entertainment.

Groups - анкеты действующих групп: Fatality.

Groups - анкеты действующих групп: Jupiter 77.

Groups - анкеты действующих групп: Proxima Centauri.

Groups - анкеты действующих групп: RaZZLeRs.

Groups - анкеты действующих групп: RUSH.

Groups - анкеты действующих групп: Smash Hackers Band.

Illegal Corner - Razzlers оправдываются за релиз демки First Association.

Illegal Corner - Scenergy Release Charts - конкурс крэков.

Illegal Corner - Welcome to Scenergy Release Charts (SRC).

Illegal Corner - софтография Fatality Group.

Lits - Pussy: история создания знаменитой игры от Fatality.

Lits - Scenergized beyond the belief.

Lits - speed.

Lits - история образования Ростовской ассоциации PartyZans.

Lits - история создания игры "Белый орел - товарищ известен".

Lits - рассказ о том как Fatality выпускает игрушки.

Mail Box - письма: Ellvis и Fatality довольны Scenergy #1, Ulterior поносит Antares и BrainWave, Realtimer разочарован.

News - Doom'a не будет!

News - Виртуальное пати Millennium, X-Raizor вернулся на сцену, Andrew Fer организовал новую группу, провал Германского пати Spectrology, новости от 3SC, Zero Team, Extreme.

News - мнение Megus'a о dentro compo СС'2000.

News - новости от OHG, Delta Hackers Group, Die Crupps, Волгодонских спектрумисто и от группы SpeedWay.

Scenergy - адреса для связи с редакцией.

Scenergy - благодарности соавторам журнала.

Scenergy - новое в облочке журнала.

Scenergy - обещанного видео в статьях не будет...

V.I.P. - Random берет интервью у Unbel!ever/Sage/XTM.

V.I.P. - The most noble tale of the scene.

V.I.P. - интервью с Arny и Mythos, создателями клона Elite игры Awaken.

V.I.P. - Интервью с Fatality, широко известными крэкерами и гейм-мэйкерами

V.I.P. - интервью с одним из авторов игры Elite.

V.I.P. - интервью с одним из самых прогрессивных художников на спектруме Diver/4D.

V.I.P. - Интервью, взятое у Random'а каким-то PC-журналом

Warez Pack - описание Inertia Player.

Warez Pack - описание демо 1140.

Warez Pack - описание импортной демки 'no work'.


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

Похожие статьи:
HOT GAMES - Лучшая десятка oт Magic Soft.
charts - booze charts v40.1%
Оттяг - Винни-Пух и все-все-все - 2.

В этот день...   28 марта