Depth #01
14 октября 1997

Программистам - совершенные методы кодинга и современные способы работы с графикой: печать спрайта, скроллинг экрана, очистка экрана, работы с двумя экранами.

________________________________________
                                        
   Tекст    :VIATOR                     
                                        
   Музыка   :COOPER                     
                                        
________________________________________
                                        
                                        
     (C) ВУ VIATOR/AVALON/RUSH/ASM      
                                        
COВEPШEHHЫE МETOДЫ КOДИHГА И COВPEМEHHЫE
       CПOCOБЫ PАБOTЫ C ГPАФИКOЙ        
                                        
    Большинство  программистов на SPECCУ
были  вынуждены  самостоятельно  изучать
ассемблер  и придумывать быстрые способы
работы   с   динамической   графикой.  К
сожалению,  ни  одной достойной книги по
данной   теме   так   и   не  появилось.
Литература    издательств    "Питер"   и
"Инфорком"   устаревала  еще  до  своего
появления. Книга,которую обещал написать
SтаlKеr,могла бы стать отличным пособием
для  кодера,  но  неизвестно появится ли
она когда-либо вообще...                
     В  последнее  время  в  электронных
изданиях   стали  публиковаться  статьи,
посвященые    профессиональным   методам
работы   с  графикой.  Hо,  как  это  не
печально,  зачастую  в  них  встречается
множество неточностей и ошибок.         
     Конечно, было бы прекрасно, если бы
подобную  статью  написал RST-7, IMP или
ALEX  RAIDER,  у  которых богатый опыт в
данной   области,  но  если  уж  они  не
удосужились  ничего  написать за столько
лет,   маловероятно,   что  они  напишут
что-либо в будущем.                     
                                        
     Как  обычно,  начнем  с  конца... и
ответим  на вопрос, который долгое время
терзал умы кодеров всех стран: "Можно ли
вывести   полноэкранную   картинку  (без
атрибутов)  на  экран за одно прерывание
?"  -  ДА  !!!  Это  вполне  возможно  и
достаточно  просто ! К сожалению, многие
программеры   считали   не  так  и  даже
посвящали этой теме статьи в журналах, в
которых приводили кучу доводов и фактов,
отвергающих   такую  возможность.  Cтоит
вспомнить хотя бы статью в первом номере
журнала    "ZX-POWER".   Cтатья   вполне
профессиональная,  но  кое-какие  ошибки
имеются.  Oшибаться  может каждый, а наш
кодерский  долг обязывает нас эти ошибки
исправлять, чем мы сейчас и займемся... 
                                        
                                        
1.     Pассмотрим     наиболее     часто
используемые  методы  вывода изображений
на экран.                               
                                        
 а).Cамый простой способ вывести спрайт-
    перебрасывать  его   последовательно
    байт  за  байтом, строку за строкой.
    прорамма,выполняющая такие действия,
    выглядит примерно так:              
                                        
       LOOP1   PUSH    ВC               
               PUSH    HL               
       LOOP2   LD      A,(DE)           
               INC     DE               
               LD      (HL),A           
               INC     L                
               DJNZ    LOOP2            
               POP     HL               
               CALL    DOWN_HL          
               POP     ВC               
               DEC     C                
               JR      NZ,LOOP1         
               RET                      
                                        
      DE-адрес спрайта в памяти,        
      HL-адрес в экране,                
      В -ширина спрайта в знакоместах,  
      C -высота спрайта в пикселях.     
      DOWN_HL - переход на строку ниже. 
                                        
 Данный   способ,   несмотря   на   свою
простоту и примитивность,вполне подходит
для   вывода   статичной   (неподвижной)
графики.                                
                                        
 Изменив входные параметры в регистрах  
 HL,DE,ВC, можно вывести картинку любого
 размера в любое место экрана. К сожале-
 нию, такая гибкость не свойственна всем
 остальным способам вывода графики.     
                                        
 б). Выводить графику с фиксированной   
     шириной.                           
                                        
    LOOP1   PUSH   DE                   
            LDI     ;колличество зависит
            ...     ;от ширины спрайта. 
            POP    DE                   
            EX     AF,AF'               
            CALL   DOWN_DE              
            EX     AF,AF'               
            DEC    A                    
            JR     NZ,LOOP1             
            RET                         
     HL-адрес спрайта в памяти,         
     DE-адрес в экране,                 
     A -высота спрайта в пикселях.      
                                        
 Этот способ несколько быстрее предыду- 
 щего, но из-за привязки к определенной 
 ширине спрайта, менее распостранен.    
                                        
 в.) Вывод графики при помощи стека.    
     Этот и следующий приемы вывода гра-
     фики  более  эффективны и быстры по
     сравнению  с  предыдущими,но вместе
     с тем и несколько сложнее.         
     Итак, пересылка стек-экран:        
     Программа    создает   при   первом
     запуске   рабочий  блок  ,  который
     собственно   и   будет   заниматься
     переброской графики.               
                                        
     Адрес  графики  заносится в регистр
     SP,   затем   значения   со   стека
     последовательно    извлекаются    и
     заносятся  в  экран.  Примерно  это
     будет выглдеть так:                
                                        
     ...                                
     POP     HL                         
     LD      (#4OOO),HL                 
     POP     HL                         
     LD      (#4OO2),HL                 
     POP     HL                         
     LD      (#4OO4),HL                 
     ...                                
                                        
        Eстественно,   что   адреса,   в
     которые  будет  бросаться  графика,
     заранее   фиксированы,   фиксирваны
     также    размеры   спрайта.   Длина
     полученой    процедуры   в   памяти
     зависит   от  размеров  спрайта,  и
     будет в два раза большей чем он. Tо
     есть, если вы перебрасываете спрайт
     на весь экран (6144б.),            
     размер программы будет - 12288б.   
         Tакое расточительство вполне   
     оправдано, так как скорость рабо-  
     ты этой программы гораздо выше чем 
     предыдущих.        Oдин        байт
     перебрасывается  за  13 тактов. Tем
     более, что до инсталляции программа
     будет  занимать  всего каких-нибудь
     1OO байтов.                        
                                        
 г). Cледующий способ похож на прдыдущий
     но более подходит  для  скроллингов
     вверх и вниз,чем для вывода графики
     Tак   как  к  определенным  адресам
     здесь  привязывается  и источник, и
     приемник.                          
                                        
     ...                                
     LD      HL,(#41OO)                 
     LD      (#4OOO),HL                 
     LD      HL,(#41O2)                 
     LD      (#4OO2),HL                 
     LD      HL,(#41O4)                 
     LD      (#4OO4),HL                 
     ...                                
                                        
     Абсолютно не используется стек и не
     изменяет регистры,за исключением HL
     Использует         на        каждый
     перебрасываемый байт графики по три
     байта        памяти.Oдин       байт
     перебрасывается за 16 тактов.      
                                        
 д).     Hаиболее    быстрым    способом
     CКPOЛЛИHГА  экрана  по  вертикали и
     довольно совершенным методом вывода
     графики    из    памяти    является
     следующий:                         
                                        
     ...                                
     LD      SP,адрес-источник          
     POP     HL                         
     POP     DE                         
     POP     ВC                         
     POP     AF                         
     POP     IX                         
     POP     IУ                         
     EXX                                
     POP     HL                         
     POP     DE                         
     POP     ВC                         
                                        
     LD      SP,адрес-цель              
     PUSH    ВC                         
     PUSH    DE                         
     PUSH    HL                         
     EXX                                
     PUSH    IУ                         
     PUSH    IX                         
     PUSH    AF                         
     PUSH    ВC                         
     PUSH    DE                         
     PUSH    HL                         
     ...                                
                                        
     Этот метод очень эффективен,но  все
     равно  не  позволяет  вывести  весь
     экран за одно прерывание.          
                                        
 е). Tеперь рассмотрим CАМЫЙ совершенный
     и  малоиспользуемый  способ  вывода
     графики:                           
     Данные перемешиваются с программой,
     и получается конструкция типа:     
                                        
     ...                                
     LD      SP,адрес в экране          
     LD      HL,два байта графики       
     PUSH    HL                         
     LD      HL,очередные два байта     
     PUSH    HL                         
     LD      HL,очередные два байта     
     PUSH    HL                         
     ...                                
                                        
     А теперь давайте немного посчитаем.
                                        
     LD    HL,число - 1O тактов,        
     PUSH  HL       - 11 тактов.        
     Для  вывода  полноэкранной картинки
     необходимо повторить этот  фрагмент
     3O72 раза = 21*3O72 = 64512 тактов.
     LD    SP,число - 1O тактов.        
     Cтек  изменять  придется( хотя и не
     обязательно )перед  выводом  каждой
     строки,то есть  192  раза = 1O*192=
     =192O тактов.                      
       И того,все в целом будет занимать
     64512+192O=66432 такта !!!         
                                        
     Как видите,все вполне бозможно и ре
     ально.Возможности  Cпектрума не ис-
     черпали себя и до сих пор !        
     SPECCУ ALIVE FOREVER !!!           
    Данный  способ вывода графики далеко
не  нов  и  придуман  не мной. Во всяком
случае им пользовались многие мои друзья
из  RUSH,  и рассказал мне о нем IMP еще
несколько лет назад...                  
    При использовании этого метода также
расходуется   по  два  байта  памяти  на
каждый  выводимый  байт  графики.  Вывод
полноэкранной   картинки  абсолютно  без
повторяющихся   фрагментов   элементарно
укладывается  не только в пентагоновское
прерывание,  а  и  в прерывание на любой
нормальной  машине,  например, SCORPION,
PROFI  и т.д. Правда на фирменной машине
появляются проблемы связанные с тем, что
в  ней  раздельные  поля памяти, то есть
экранная    память    работает   гораздо
медленее, а нам приходится помещать стек
в экран...                              
 Hо  если  бы  у  фирменного SPECCУ было
реально  7OOOO  тактов в прерывании, все
отлично   успевало   бы  работать,  даже
осталось бы место для музыки.           
      4тоб     заставить     изображение
двигаться,   придется   менять   адреса,
заносимые в SP, но и это вполне реально.
Oстается лишь сказать, что в нашей новой
демке  "HALLUCINATIONS OPERA" есть такой
FX,  правда  на  весь  экран он работает
только  на  Пентагоне,  но надо же иметь
совесть, как говорит наш 3нахарь...     
                                        
                                        
                                        
    И еще несколько полезных советов для
кодеров,   которые  были  почерпнуты  из
многолетнего  опыта работы на ассемблере
как  моего  личного, так и многих других
кодеров:                                
                                        
     При  выводе  изображения  по маске,
спрайт     удобнее     всего     хранить
перемешанным  с  маской.  Байт  графики,
затем байт маски и т.д. Выводиться такой
спрайт будет так:                       
                                        
       ...                              
       POP     DE    ; два байта графики
       LD      A,D                      
       AND     (HL)                     
       OR      E                        
       LD      (HL),A                   
       INC     L                        
       ...                              
Cтек   при   этом  должен  указывать  на
графику, а HL на экран.                 
                                        
                                        
                                        
   Hаиболее  быстрый  способ очистки эк-
рана:                                   
                                        
       LD      SP,#58OO                 
       LD      ВC,O                     
       PUSH    ВC - повторить 3O72 раза.
                                        
Tакже  можно  очищать  любые  области  в
памяти   и   т.п.   Конечно   вовсе   не
обязательно   делать   такие   процедуры
абсолютно  без  циклов. Можно, например,
сделать  всего  256 PUSH'ей, и зациклить
этот блок нужное колличество раз. Oсобых
потерь в скорости не будет.             
                                        
                                        
                                        
   Tеперь  очень  важная  вещь,  которую
следует  знать  всем,  кто  решил писать
качественные  программы  на  SPECCУ. При
выводе   большого   количества  графики,
вероятность  того, что телевизионный луч
пересечется  с выводимым в данный момент
блоком   графики   очень   велика.   Это
приведет к тому, что в месте пересечения
с  лучем, динамическое изображение будет
дискрировать.  Hапример,  при скроллинге
большого  фрагмента экрана верхняя часть
его  будет сдвинута, затем луч "догонит"
место   вывода,  и  дальнейшая  половина
картинки  будет выводиться с отставанием
на  один кадр. Eще более ужасная картина
получается,  если  изображение на экране
времменно   стирается,  развертка  может
попасть  именно на такой момент, и тогда
могут   появиться   исчезающие  спрайты,
промигивающие     курсоры    и    прочее
ламерство.                              
                                        
     Как с этим бороться:               
Можно  постараться,  чтобы  развертка не
пересекалась  с  выводом  на  протяжении
всего  прерывания.  Tак,  можно  сначала
вывести графику в среднюю и нижнюю трети
экрана,   а  в  конце,  когда  лучь  уже
пройдет  верхнюю  половину экрана, можно
вывести   верхнюю   треть.   Этот  метод
используется  довольно  часто,  но из-за
огромных    различий    в    конструкции
компьютеров  развертка  на  разных типах
SPECCУ   может  сильно  отличаться,  что
станет       причиной      дискрирования
изображения.    Cтоит   посмотреть   как
работает "SHOCК" на Пентагоне, и вам все
станет ясно.                            
     Cамым   эффективным   и  практичным
методом   в   данном   случае   является
использование  дополнительного  экрана в
машинах  с  O3У  128к  и больше. Hаличие
двух  экранов, которые можно переключить
мгновенно      при     помощи     одного
единственного    OUT'а,   очень   сильно
облегчает жизнь программисту.           
     Pабота     с     двумя     экранами
производится   следующим   образом:   на
прерывания   (не  обязательно)  вешается
небольшая  программа, которая поочередно
подключает   то  7  страницу  и  обычный
экран,  то  5  страницу и теневой экран.
Выглядеть это может примерно так:       
                                        
SCREEN_СHANGER:                         
                                        
SCR     LD      A,#55       ; %O1O1O1O1 
        RRCA                            
        LD      (SCR+1),A               
        LD      A,#17       ; 16+7      
        JR      C,PAGER                 
        LD      A,#1D       ; 24+5      
PAGER:                                  
        LD      ВC,#7FFD    ; 32765     
        OUT     (C),A                   
        RET                             
                                        
   Все  процедуры, работающие с экраном,
должны  быть написаны с учетом того, что
экран теперь находится не с адреса #4OOO
(16384  dес),  а  с  адреса #COOO (49152
dес). Процедуру DOWN_HL менять не нужно,
она и так будет работать корректно.     
     Cуть  данного метода состоит в том,
что  изменять  (стирать, двигать и т.д.)
Вы   будете   не   тот   экран,  который
отображается    в   данный   момент   на
мониторе,  а  тот,  который  находится в
памяти  и  не  виден  зрителю. Hикакого,
дискрирования  не  будет абсолютно, даже
если   Вы  будете  изменять  весь  экран
целиком.    Tак   например   сделано   в
словацкой   демке   "ECHOLOGУ",   и  она
великолепно  работает  на  всех машинах,
вкючая    Пентагон,    за    исключением
MULTICOLOR'ов,    разумеется.    Кстати,
MULTICOLOR - это и есть дискрирование...
      Конечно писать программы используя
один  экран  - круче, но на практике это
не   целесообразно.  Я  советую  Вам  не
мучить  пользователей  и писать sоfт под
два экрана.                             
                                        
                                        
    А  теперь  совет, не имеющий прямого
отношения   к   работе   с  динамической
графикой,  но он может пригодиться Вам в
том   случае,  если  у  Вас  не  хватает
процессорного  времени  на  проигрывание
музыки,   а  свободной  памяти  остается
много.  В  таком  случае можно поступить
следующим образом:                      
      Музыка      раскладывается      на
составляющие    компоненты    и    затем
проигрывается   минуя   рlаyеr.  Простой
вывод  данных  в  порты  будет  занимать
каких-нибудь 3OO тактов, если сравнить с
тем,  что  рlаyеr от "ASM" требует более
8OOO тактов - разница ощутима.          
      Желательно   не   подгружать   уже
разложенную  на данные музыку с диска, а
создавать   ее   непосредственно   перед
запуском  программы  ,  так-как  размеры
полученного блока данных могут достигать
десятков    киллобайт.    Можно    также
попробовать              компрессировать
повторяющиеся фрагменты.                
      Данный   метод   использовался  во
многих    демонстрациях   -   "ECSTASУ",
"SHOCК", "SATISFACTION", "INSULT" и др. 
                                        
                                        
    А вот наиболее  красивый  и компакт-
ный   способ  отключения  звука  на  AУ,
который я видел (писал его не я):       
                                        
SHUT_UP:                                
          LD      HL,#OOOD              
SHUT1     LD      ВC,#FFFD              
          OUT     (C),L                 
          LD      В,#ВF                 
          OUT     (C),H                 
          DEC     L                     
          JR      NZ,SHUT1              
          RET                           
                                        
                                        
    Eсли  кто-то  не понял, что именно я
имел  в  виду под процедурой DOWN_HL или
DOWN_DE, я привожу ниже их текст:       
                                        
DOWN_HL:                                
          INC     H                     
          LD      A,H                   
          AND     7                     
          RET     NZ                    
          LD      A,L                   
          ADD     A,#2O                 
          LD      L,A                   
          RET     C                     
          LD      A,H                   
          SUВ     8                     
          LD      H,A                   
          RET                           
                                        
DOWN_DE:                                
          INC     D                     
          LD      A,D                   
          AND     7                     
          RET     NZ                    
          LD      A,E                   
          ADD     A,#2O                 
          LD      E,A                   
          RET     C                     
          LD      A,D                   
          SUВ     8                     
          LD      D,A                   
          RET                           
                                        
                                        
                                        
   Иногда бывает нужно пересчитать адрес
в экране в адрес соответствующий данному
знакоместу  в области атрибутов. Cделать
это можно так:                          
                                        
SCR_ATR:                                
          LD      A,H                   
          RRCA                          
          RRCA                          
          RRCA                          
          AND     3                     
          OR      #58                   
          LD      H,A                   
          RET                           
                                        
                                        
    Hа    сегодня    хватит...   Конечно
способов     повышения     эффективности
программ    может    быть    бесконечное
множество.   Для   каждого   конкретного
случая  есть  свои приемы и тонкости. Их
нужно  знать  не  только для того, чтобы
писать сногсшибательные эффекты...      
      Hе  умея пользоваться достижениями
современных   кодеров,   вы  не  сможете
писать     качественные     динамические
игрушки,    да   и   хорошей   системной
программы написать невозможно, пользуясь
методами десятилетней давности.         
     Поэтому  дерзайте ! Возможно, скоро
Вам   удастся   написать   полноэкранный
мulтiсоlоr  или  еще  какое-нибудь  чудо
кодинга !                               
                                        
             Gооd luсK !!!              
                                        
P.S.       Hеплохо      бы      написать
профессиональную  книгу  по  кодингу,  в
которой   были  бы  описаны  все  методы
      Hе  умея пользоваться достижениями
современных   кодеров,   вы  не  сможете
писать     качественные     динамические
игрушки,    да   и   хорошей   системной
программы написать невозможно, пользуясь
методами десятилетней давности.         
     Поэтому  дерзайте ! Возможно, скоро
Вам   удастся   написать   полноэкранный
мulтiсоlоr  или  еще  какое-нибудь  чудо
кодинга !                               
                                        
             Gооd luсK !!!              
                                        
P.S.       Hеплохо      бы      написать
профессиональную  книгу  по  кодингу,  в
которой   были  бы  описаны  все  методы
программирования  и  множество  полезных
процедур.  Возможно, если ктонибудь меня
попросит, я мог бы попробовать написать,
что-то подобное...                      
                                        



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

От авторов - Hесколько слов о пушистом чуде техники.

Авторы - авторы журнала.

В приложении - демо-версия игры "CМАГЛИ-3".

Фантастика - крыса из нержавеющей стали (часть 1).

Фантастика - крыса из нержавеющей стали (часть 2).

Фантастика - крыса из нержавеющей стали (часть 3).

Фантастика - крыса из нержавеющей стали (часть 4).

Фантастика - крыса из нержавеющей стали (часть 5).

Фантастика - крыса из нержавеющей стали (часть 6).

Фантастика - крыса из нержавеющей стали (часть 7).

Фантастика - крыса из нержавеющей стали (часть 8).

Фантастика - крыса из нержавеющей стали (часть 9).

Фантастика - Арест: Любое подобие имен и случаев в этом рассказе является не случайным.

Программистам - 14 советов пишещему boot, советы пищущему Компрессор, несколько советов пищущемо Музыкальный редактор. Рекомендации автору Alasm и STS.

Программистам - совершенные методы кодинга и современные способы работы с графикой: печать спрайта, скроллинг экрана, очистка экрана, работы с двумя экранами.

Программистам - Формат модулей NоisеTrасKеr/SоundTrасKеr/PrоTrасKеr.

Железо - доработки Скорпиона: Covox.

Железо - доработки Скорпиона: схема корректной дешифрации портов музпроцессора.

Железо - доработки Скорпиона: схема отключения музпроцессора.

Железо - квадросистема: подключение 2х AY.

Проект - новый графический редактор - State of Art.

Разное - Aмаzing Sоfтwаrе MаKing - почему название такое не звучное и с позволения сказать тупое?

Разное - новости - Планируется куча игр: Крестики-нолики, Куча пародий на уже вышедшие игры, 3D Леталка, Классную стратегию.

Разное - Приветы ! Кто их не любит ? Поищите, может и себя здесь найдете.

Разное - операция "в поисках сьюзан".

Юмор - как Avalon готовились к Enlight 1997.

Юмор - Как затащить хакера в спальню.

Юмор - Как затащить хакера в спальню.

Эсперанто - справочник по языку Эсперанто.

Реклама - Продажа , покупка и обмен нового программного обеспечения для Спектрума.


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

Похожие статьи:
Почти невинная история
Обзор - обзор выпусков MSD.
Вступление - содержание номера.

В этот день...   15 декабря