Элементарная графика 1993 г.

Практикум по графике в машинных кодах - стандартный формат функции пользователя. Очистка заданного окна экрана. Окрашивание заданного окна цветом INK. Окрашивание заданного окна цветом PAPER.


                    3. ПРАКТИКУМ ПО ГРАФИКЕ В МАШИННЫХ КОДАХ

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

              Если Вы дочитали книгу до этого раздела, то уже хорошо се-
         бе представляете, что говоря  о графике мы прибегаем  к БЕЙСИКу
         только на уровне идей и концепций, а как только дело доходит до
         конкретных практических  применений, нам  приходится задейство-
         вать машинный  код. И  все-таки жаль  расставаться с  БЕЙСИКом,
         ведь с  ним все  так просто,  что не  использовать эту простоту
         было бы неразумно.

              Желая сохранить простоту БЕЙСИКа и быстродействие машинно-
         кодовых процедур, мы организовали их совместное использование в
         рамках данной главы. БЕЙСИКу отводится роль связующего звена, а
         также  блока  логики  верхнего  уровня,  а  конкретные операции
         выполняет машинный код, представленный разными процедурами.

              Существуют различные способы объединения в единой структу-
         ре и БЕЙСИКа и машинного  кода. Так, на страницах наших  книг и
         журналов мы не раз говорили о введении машинного кода в БЕЙСИК-
         строку за оператором REM. Вместе с тем, один из широко  распро-
         страненных приемов, связанный с использованием функций  пользо-
         вателя FN до сих пор не нашел должного освещения в наших  рабо-
         тах, о чем приходится сожалеть. Дело в том, что это тоже  очень
         удобный прием,  который становится  особенно незаменимым  в тех
         случаях, когда при  вызове машиннокодовой процедуры  из БЕЙСИКа
         надо передать в нее ряд параметров.

              Обычный прием по передаче параметров из БЕЙСИКа в машинный
         код состоит в том, что  в оперативной памяти Вы выделяете  нес-
         колько ячеек памяти для хранения этих параметров, т.е.  исполь-
         зуете эти адреса, как адреса программных переменных. Затем, пе-
         ред  вызовом  машиннокодовой  процедуры,  выставляете с помощью
         оператора POKE нужный Вам параметр в его ячейке памяти NN,  вы-
         зываете  процедуру,  она  "подхватывает"  Ваш  параметр из этой
         ячейки, отправляет в регистр процессора, работает с ним и, если
         нужно вернуть какой-то результат работы, тоже отправляет его  в
         заранее  зарезервированную  ячейку  памяти,  например MM, после
         чего возвращается в БЕЙСИК. В БЕЙСИКе Вы можете с помощью  опе-
         ратора  PEEK  MM  "прощупать", что  же там наработала Ваша про-
         цедура.

              Это стандартный прием.  Его используют, например,  большие
         программы, целиком написанные  в машинном коде.  Так передаются
         параметры из одних процедур в  другие. Для того, чтобы все  это
         хорошо  работало,  программист  обычно  отводит  солидный  блок
         памяти  (несколько  сотен  байтов)  для  хранения  в  нем таких
         программных переменных и строго  следит, чтобы ничто этот  блок
         во время работы программы не затерло.

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

              Если для программ, целиком написанных в машинном коде, это
         неудобство  является  необходимым  злом,  то для нашего случая,
         когда мы объединяем  БЕЙСИК и машинный  код в одной  структуре,
         есть элегантный  прием для  передачи параметров,  основанный на
         использовании в БЕЙСИКе  функций, определенных пользователем  и
         мы его сейчас рассмотрим,  но сначала остановимся на  вопросе о
         том, как хранятся в  БЕЙСИКе функции  пользователя.

              ВНИМАНИЕ! Перед тем, как начинать работу с этой главой,
                        необходимо внимательно изучить раздел 2.9.

                3.1. Стандартный формат              +-----------------+
                   функции пользователя.             ¦ ЫЯЯЯЯЬ    ЯЫЯ   ¦
                                                     ¦ Ы    Ы     Ы    ¦
               Давайте  немного  поэкспериментируем. ¦ ЫЯЯЯЯЬ     Ы    ¦
         Наберите на БЕЙСИКе следующую программу:    ¦ Ы    Ы Ь  ЬЫЬ Ь ¦
                                                     +-----------------+
                      10 DEF FN a(x,y,z)=x+y+z
                      20 FOR i=23755 TO 24000
                      30 PRINT i, PEEK i
                      40 NEXT i

              Вы, очевидно знаете, что  начиная с адреса 23755  в памяти
         компьютера  располагается текст БЕЙСИК-программы, поэтому выше-
         приведенная программа делает ничто иное, как распечатывает этот
         текст байт за байтом. Результат ее работы будет следующим:

         23755         0  Дї
         23756        10  ДЩ - номер строки БЕЙСИКа;
         23757        34  Дї
         23758         0  ДЩ - длина этой строки (34 байта);
         23759       206     - код оператора DEF FN;
         23760        97     - код буквы a;
         23761        40     - код открывающей скобки;
         23762       120     - код буквы x;
         23763        14     - код, свидетельствующий, что следующие 5
                               байтов выражают некоторое действительное
                               число, записанное в интегральной форме;
         23764       121 Дї
         23765        44  Ё    полная "абракадабра", совершенно непо-
         23766       122  ГД - нятно, что это за число. То ли очень
         23767        41  Ё    большое, то ли очень маленькое.
         23768       120 ДЩ
         23769        44     - код запятой;
         23770       121     - код буквы y;
         ...................   и так далее.

              Давайте поставим второй эксперимент:

              10 DEF FN a(x,y,z)=x+y+z
              15 LET test=FN a(3,8,5*2-7)
              20 FOR i=23755 TO 24000
              30 PRINT i, PEEK i
              40 NEXT i

              Мы добавили в программу строку 15, а теперь опять   распе-
         чатаем текст строки 10, дав команду RUN. Вы получите результат:
         ...........................................
         23762       120     - код буквы x;
         23763        14
         23764         0 Дї
         23765         0  Ё
         23766         3  ГД -  код числа 3.
         23767         0  Ё
         23768         0 ДЩ
         23769        44     - код запятой;
         23770       121     - код буквы y;
         23771        14
         23772         0 Дї
         23773         0  Ё
         23774         8  ГД -  код числа 8.
         23775         0  Ё
         23776         0 ДЩ
         ................... -  и т.далее

              То, что мы сейчас увидели - довольно интересный результат.
         Фактически наличие  в программе  строки с  номером 15  изменило
         содержание строки 10. С  таким нечасто удается сталкиваться.  А
         происходит  это  потому,  что  в  "Спектруме", когда Вы задаете
         определение функции DEF FN и указываете ее параметры  x,y,z,...
         и пр., за каждым именем параметра сразу резервируются 5 байтов,
         в которых  впоследствии будут  располагаться числовые  значения
         этих параметров.

              Как только встретился  вызов функции FN  в строке 15,  эти
         параметры были вычислены и подставлены или просто  подставлены,
         если их не надо вычислять, в забронированное место в строке 10.

             Таким образом, непосредственно в БЕЙСИК-строке  организован
         буфер, в котором хранятся текущие значения параметров. Сравните
         с программными переменными, текущие значения которых хранятся в
         специально  отведенной  области  памяти,  на  которую указывает
         системная переменная VARS (23627 = 5C4B).

              Так как ко  времени вычисления функции  пользователя пара-
         метры расставлены по своим местам, то их можно было бы  исполь-
         зовать  для  передачи  данных  в  машинный код, если бы удалось
         точно определить адреса этих мест или привязать их к чему-либо.
         И эта возможность имеется.

              В наборе системных переменных  компью- +-----------------+
         тера  есть   системная  переменная   DEFADD ¦  ЬЬЬЬ     ЬЬЬ   ¦
         (23563 = 5C0BH),  которая в момент  расчета ¦ Ы    Ы     Ы    ¦
         функции пользователя содержит в себе адрес, ¦  ЯЬ        Ы    ¦
         с которого начинаются параметры этой  функ- ¦    ЯЬ      Ы    ¦
         ции. В прочие моменты времени там  хранится ¦ Ы    Ы     Ы    ¦
         0.  Если  бы  Вам  удалось  распечатать  ее ¦  ЯЯЯЯ  Я  ЯЯЯ Я ¦
         содержимое в момент расчета фунуции FN a,то +-----------------+
         Вы получили бы 23762, т.е.  она указывает на имя первого  пара-
         метра - "x". А дальше все просто. Если мы будем передавать  че-
         рез параметры процедуры целые  числа, лежащие в интервале  от 0
         до 255, то первое число будет находиться по адресу  (DEFADD)+4,
         там сейчас стоит  число "3", второе  - (DEFADD)+12 -  там сечас
         стоит параметр y, равный восьми, третье - (DEFADD)+20 и т.д.  с
         шагом по восемь  байтов (один байт  на букву, обозначающую  имя
         этого параметра, один  байт на запятую,  разделяющую параметры,
         один байт на символ CHR14  и пять байтов на интегральную  форму
         числа.)

              Так можно  использовать передачу  параметров из  БЕЙСИКа в
         машинный  код  через  параметры  функции  пользователя. В нашем
         случае мы будем передавать целые  числа от 0 до 255,  т.е. один
         байт, но конечно можно передавать и любые действительные числа,
         что делает этот метод наиболее удобным. В этом случае  передан-
         ная пятибайтная форма готова для обработки в калькуляторе.

                   3.2   Очистка заданного окна экрана.

              Мы разберм эту процедуру самым подробнейшим образом. В от-
         личие от обычной процедуры  CLS, она позволяет очищать  не весь
         экран,  а  заданное  окно,  параметры  которого  выставляются в
         БЕЙСИКе в функции FN  a(x,y,h,v). В качестве начального  адреса
         процедуры мы выбрали 63000, ее  длина - 92 байта и  еще  четыре
         байта в конце процедуры отведены для хранения рабочих  парамет-
         ров. Список параметров:

              x - горизонтальная координата левого верхнего угла окна,
                  подлежащего очистке (задается в знакоместах 0...31);
              y - вертикальная координата левого верхнего угла окна,
                  подлежащего очистке (задается в знакоместах 0...23);
              h - горизонтальный размер окна в знакоместах (h+x<32);
              v - вертикальный размер окна в знакоместах (v+y<24).

              Эта процедура  может обслуживать  весь экран,  то есть все
         двадцать четыре символьных ряда, а не только главную его часть,
         т.е. 22 ряда. Если Вы зададите начальный параметр y больше, чем
         23, процедура вернется в БЕЙСИК не работая, но на параметры  x,
         h и v перехват ошибок не поставлен, чтобы не усложнять машинный
         код, так что здесь ошибка может привести к зависанию или сбросу
         компьютера, впрочем, при практическом использовании такой  про-
         цедуры Вы сможете поставить  перехват например в БЕЙСИКе  перед
         вызовом FN a.

                    10 REM *** Загрузчик машинного кода
                    20 LET adr=63000: LET long=95: LET z=0
                    30 FOR i=0 TO long-1: READ a
                    40 POKE (adr+i),a: LET z=z+a
                    50 NEXT i
                    60 LET z=INT (((z/long)-INT (z/long))*long)
                    70 READ a
                    80 IF a<>z THEN PRINT "??": STOP
                    90 REM
                   100 REM *** Пример использования процедуры
                   110 DEF FN a(x,y,h,v)=USR 63000
                   120 BORDER 4: PAPER 1: INK 6: CLS
                   130 FOR n=0 TO 703
                   140 PRINT "ЯЬ";
                   150 NEXT n
                   160 PAUSE 100
                   170 FOR n=1 TO 5
                   180 RANDOMIZE FN a(n*6-5,n*3-1,5,5)
                   190 NEXT n
                   200 REM *** Данные для машинного кода
                   210 DATA  42,  11,  92,   1,   4
                   220 DATA   0,   9,  86,   1,   8
                   230 DATA   0,   9   94, 237,  83
                   240 DATA 116, 246,   9,  86,   9
                   250 DATA  94, 237,  83, 118, 246
                   260 DATA 237,  91, 116, 246, 123
                   270 DATA 254,  23, 240, 237,  83
                   280 DATA 116, 246, 123, 230,  24
                   290 DATA 246,  64, 103, 123, 230
                   300 DATA   7, 183,  31,  31,  31
                   310 DATA  31, 130, 111,  58, 118
                   320 DATA 246,  71, 197, 229,   6
                   330 DATA   8, 197, 229,  58, 119
                   340 DATA 246,  71, 175, 119,  35
                   350 DATA  16, 252, 225, 193,  36
                   360 DATA  16, 240, 225, 193,  62
                   370 DATA  32, 133, 111,  48,   4
                   380 DATA  62,   8, 132, 103,  16
                   390 DATA 222, 201,   0,   0,   0
                   400 DATA  82

              Дисассемблер машинного кода представлен ниже. Таким  обра-
         зом, фактически здесь и далее Вы имеете распечатку каждой  про-
         цедуры,  повторенную трижды.  Первый раз в десятиричном  виде в
         строках DATA, второй раз - то же самое в шестнадцатиричном коде
         и третий раз - в виде мнемоник АССЕМБЛЕРа. Такой тройной повтор
         сделан не только для того, чтобы каждый мог работать с тем  ко-
         дом, который ему удобнее, но и из соображений надежности, в ка-
         честве дополнительной меры по борьбе с опечатками.

              На первом этапе процедура принимает параметры x,y,h и v и
         перебрасывает их в ячейки 63092...63095.

         63000   2A0B5C        LD HL,(5C0BH)  ;DEFADD - системная пере-
                                              ;менная, указывающая на
                                              ;то, где находятся пара-
                                              ;метры функции пользова-
                                              ;теля. Ее адрес 5C0BH
                                              ;(23563).
         63003   010400        LD BC,0004     ;Сдвиг от DEFADD на 4 бай-
         63006       09        ADD HL,BC      ;та (см. выше).
         63007       56        LD D,(HL)      ;Координата x.
         63008   010800        LD BC,0008     ;Сдвиг от DEFADD еще на 8
         63012       09        ADD HL,BC      ;байтов (см. выше).
         63013       5E        LD E,(HL)      ;Координата y.
         63014 ED5374F6        LD(COORD),DE   ;Переброска параметров y
                                              ;и x в адреса 63092,63093.
         63018       09        ADD HL,BC      ;Еще сдвиг на 8 байтов.
         63019       56        LD D,HL        ;Ширина окна.
         63020       09        ADD HL,BC      ;Еще сдвиг на 8 байтов.
         63021       5E        LD E,(HL)      ;Высота окна.
         63022 ED5376F6        LD(PARAM),DE   ;Переброска параметров v
                                              ;и h в адреса 63094,63095.

              Теперь процедура  проверяет не  выходит ли  параметр y  за
         допустимый предел и начинает вычислять адрес в экранной области
         памяти,  соответствующий  координатам   левого  верхнего   угла
         заданного окна.

         63026 ED5B74F6        LD DE,(F674)   ;Координаты x и y.
         63030       7B        LD A,E         ;Координата y.
         63031     FE17        CP 17          ;Проверка на <=23.
         63033       F0        RET P          ;Выход, если больше.
         63034 ED5374F6        LD(F674),DE    ;Координаты x и y.
         63038       7B        LD A,E         ;Координата y.
         63039     E618        AND 18         ;є Расчет адреса
         63041       F6        OR 40          ;є по координатам.
         63042       67        LD H,A         ;є
         63043       7B        LD A,E         ;є
         63044     E607        AND 07         ;є
         63046       B7        OR A           ;є
         63047       1F        RRA            ;є
         63048       1F        RRA            ;є
         63049       1F        RRA            ;є
         63050       1F        RRA            ;є
         63051       82        ADD A,D        ;є
         63052       6F        LD L,A         ;є

               Теперь регистры H и L полностью соответствуют рис. 16  на
         стр. 86, т.е. мы выставили  в HL адрес дисплейной памяти,   со-
         ответствующий  нулевой  линии  левого  верхнего угла окна. Наша
         следующая задача  - непосредственная  очистка окна,  которую мы
         будем  делать,  засылая  нули  в ячейки памяти, соответствующие
         линиям входящих в окно знакомест.

              Здесь нам придется  организовать несколько вложенных  цик-
         лов. Первый цикл (внешний) - по вертикали, то есть по рядам  от
         1 до параметра v. Второй цикл (средний) - по линиям в ряду - от
         1 до 8. И третий цикл (внутренний) - по горизонтали, то есть по
         столбцам - от 1 до параметра h.

         63053   3A76F6        LD A,(F676)    ;Параметр v
         63056       47        LD B,A         ;В регистре "В" он будет
                                              ;счетчиком цикла.
         63057       C5 LOOP_V PUSH BC        ;Сохранили его на стеке
         63058       E5        PUSH HL        ;Сохранили текущий адрес.
         63059     0608        LD B,08        ;Счетчик цикла по линиям.
         63061       C5 LOOP_8 PUSH BC        ;Сохранили его на стеке
         63062       E5        PUSH HL        ;Сохранили на стеке
                                              ;текущий адрес.
         63063   3A77F6        LD A,(F677)    ;Параметр h
         63066       47        LD B,A         ;Счетчик цикла по столбцам
         63067       AF        XOR A          ;Это простейший способ об-
                                              ;нуления аккумулятора.
         63068       77 LOOP_H LD(HL),A       ;Начало цикла по столбцам.
                                              ;Очистка одной линии.
         63069       23        INC HL         ;Переход на соседнее зна-
                                              ;коместо враво.
         63070     10FC        DJNZ LOOP_H    ;Конец цикла по столбцам.
         63072       E1        POP HL         ;Восстановление данных со
         63073       C1        POP BC         ;стека.
         63074       24        INC H          ;Переход к следующей линии
                                              ;в данном ряду.
         63075     10F0        DJNZ LOOP_8    ;Конец цикла по линиям.
         63077       E1        POP HL         ;Восстановление данных со
         63078       C1        POP BC         ;стека.
         63079     3E20        LD A,20        ;Переход
         63081       85        ADD A,L        ;на следующий
         63082       6F        LD L,A         ;ряд.
         63083     3004        JR NC,NO_SEG   ;Здесь может возникнуть
                                              ;переход из сегмента в се-
                                              ;гмент. Если этого нет, то
                                              ;переход на метку NO_SEG.
         63085     3E08        LD A,08        ;Корректировка
         63087       84        ADD A,H        ;в HL
         63088       67        LD H,A         ;номера сегмента.
         63089     10DE NO_SEG DJNZ LOOP_V    ;Конец цикла по рядам.
         63091       C9        RET            ;Выход из программы.
         63092     0000 COORD  DEFW 0000
         63094     0000 PARAM  DEFW 0000

                   3.3. Окрашивание заданного окна цветом INK.

              Аналогично предыдущей процедуре, параметры заданного окна,
         выставляются  в  БЕЙСИКе  с  помощью  пользовательской  функции
         FN b(x,y,h,v,c,b,f). Начальным  адресом взят для  примера адрес
         62800, длина процедуры - 127 байтов и еще пять байтов в  конце
         отведены для хранения рабочих переменных. Список параметров:

              x - горизонтальная координата левого верхнего угла окна,
                  подлежащего очистке (задается в знакоместах 0...31);
              y - вертикальная координата левого верхнего угла окна,
                  подлежащего очистке (задается в знакоместах 0...23);
              h - горизонтальный размер окна в знакоместах (h+x<32);
              v - вертикальный размер окна в знакоместах (v+y<24).
              c - заданный цвет INK (0...7);
              b - признак яркости BRIGHT (0,1);
              f - признак мигания FLASH (0,1).

              Эта процедура также может обслуживать весь экран - все  24
         строки, а не только 22 строки основной его части.

                    10 REM *** Загрузчик машинного кода
                    20 LET adr=62800: LET long=130: LET z=0
                    30 FOR i=0 TO long-1: READ a
                    40 POKE (adr+i),a: LET z=z+a
                    50 NEXT i
                    60 LET z=INT (((z/long)-INT (z/long))*long)
                    70 READ a
                    80 IF a<>z THEN PRINT "??": STOP
                    90 REM
                   100 REM *** Пример использования процедуры
                   110 DEF FN b(x,y,h,v,c,b,f)=USR 62800
                   120 BORDER 0: PAPER 0: INK 4: CLS
                   130 FOR n=0 TO 703
                   140 PRINT "ЯЬ";
                   150 NEXT n
                   160 PAUSE 100
                   170 FOR n=1 TO 7
                   180 RANDOMIZE FN b(0,n*3-3,32,3,8-n,0,0)
                   190 NEXT n
                   200 FOR n=1 TO 7
                   210 RANDOMIZE FN b(n*4-1,0,2,22,n,0,0)
                   220 NEXT n
                   300 REM *** Данные для машинного кода
                   310 DATA  42,  11,  92,   1,   4
                   320 DATA   0,   9,  86,   1,   8
                   330 DATA   0,   9   94, 237,  83
                   340 DATA 210, 245,   9,  86,   9
                   350 DATA  94, 237,  83, 208, 245
                   360 DATA   9, 126, 230,   7,  50
                   370 DATA 207, 245,   9, 126, 230
                   380 DATA   1,  40,   8,  58, 207
                   390 DATA 245, 246,  64,  50, 207
                   400 DATA 245,   9, 126, 230,   1
                   410 DATA  40,   8,  58, 207, 245
                   420 DATA 246, 128,  50, 207, 245
                   430 DATA 237,  91, 210, 245,  58
                   440 DATA 208, 245, 254,   0, 200
                   450 DATA 237,  83, 210, 245, 123
                   460 DATA 230,  24, 203,  63, 203
                   470 DATA  63, 203,  63, 246,  88
                   480 DATA 103, 123, 230,   7, 183
                   490 DATA  31,  31,  31,  31, 130
                   500 DATA 111,  58, 208, 245,  71

                   510 DATA 197, 229,  58, 209, 245
                   520 DATA  71, 126, 230,  56,  79
                   530 DATA  58, 207, 245, 177, 119
                   540 DATA  35,  16, 244, 225,   1
                   550 DATA  32,   0,   9, 193,  16
                   560 DATA 230, 201,   0,   0,   0
                   570 DATA  46,   0

              Основным отличием  этой процедуры  от предыдущей  является
         то, что  она демонстрирует  не операции  с памятью  дисплейного
         файла, а операции с файлом атрибутов. Теперь начальный адрес  в
         HL выставляется в соответствии с файлом атрибутов (см. рис.17
         на стр. 89).

              Здесь для выполнения работы достаточно не трех циклов, как
         при обслуживании  дисплейного файла,  а только  двух - внешнего
         цикла по вертикали (параметр v) и внутреннего - по  горизонтали
         (параметр h), т.к. цикл по восьми линиям уже не нужен.

              Обратите внимание  на то,  что под  три параметра  c,b и f
         отводится всего одна ячейка памяти. В ней параметру c  отведены
         биты 0,1,2, параметру b  - бит 6 и  параметру f - бит  7. Все в

         полном соответствии с раскладкой атрибутов по битам (рис. 8).

                          Дисассемблер программы:

         62800   2A0B5C        LD HL,(5C0BH)  ;См. с. 109...111?
         62803   010400        LD BC,0004     ;Сдвиг от DEFADD на 4 бай-
         62806       09        ADD HL,BC      ;та (см. c. 109...111).
         62807       56        LD D,(HL)      ;Координата x.
         62808   010800        LD BC,0008     ;Сдвиг от DEFADD еще на 8
         62811       09        ADD HL,BC      ;байтов (см.c.109...111)
         62812       5E        LD E,(HL)      ;Координата y.
         62813 ED53D2F5        LD(COORD),DE   ;Переброска параметров y
                                              ;и x в адреса 62930,62931.
         62817       09        ADD HL,BC      ;Еще сдвиг на 8 байтов.
         62818       56        LD D,HL        ;Ширина окна.
         62819       09        ADD HL,BC      ;Еще сдвиг на 8 байтов.
         62820       5E        LD E,(HL)      ;Высота окна.
         62821 ED53D0F5        LD(PARAM),DE   ;Переброска параметров v
                                              ;и h в адреса 62928,62929.
         62825       09        ADD HL,BC      ;Следующий параметр (INK)
         62826       7E        LD A,(HL)      ;помещен в аккумулятор.
         62827     E607        AND 07         ;и переправлен в отведен-
         62829   32CFF5        LD (INK),A     ;ную ему ячейку 62927.
         62832       09        ADD HL,BC      ;Параметр (BRIGHT)
         62833       7E        LD A,(HL)      ;принимается,
         62834     E601        AND 01         ;выделяется,
         62836     2808        JR Z,SKIP_1    ;и, если не равен нулю,
         62838   3ACFF5        LD A,(INK)     ;то в параметре INK
         62841     F640        OR 40          ;включается 6-ой бит
         62843   32CFF5        LD (INK),A     ;и INK сохраняется.
         62846       09 SKIP_1 ADD HL,BC      ;Параметр (FLASH)
         62847       7E        LD A,(HL)      ;принимается,
         62848     E601        AND 01         ;выделяется,
         62850     2808        JR Z,SKIP_2    ;и, если не равен нулю,
         62852   3ACFF5        LD A,(INK)     ;то в параметре INK
         62855     F680        OR 80          ;включается 7-ой бит
         62857   32CFF5        LD (INK),A     ;и INK сохраняется.
         62860 ED5BD2F5 SKIP_2 LD DE,(COORD)  ;Координаты x,y.
         62864   3AD0F5        LD A,(F5D0)    ;Высота окна (v)
         62867     FE00        CP 00          ;Проверка высоты на ноль.
         62869       C8        RET Z          ;Выход, если так
         62870 ED53D2F5        LD (COORD),DE  ;Координаты y,x.
         62874       7B        LD A,E         є
         62875     E618        AND 18         є
         62877     CB3F        SRL A          є  Расчет адреса по
         62879     CB3F        SRL A          є  координатам.
         62881     CB3F        SRL A          є
         62883     F658        OR 58          є
         62885       67        LD H,A         є
         62886       7B        LD A,E         є
         62887     E607        AND 07         є
         62889       B7        OR A           є
         62890       1F        RRA            є
         62891       1F        RRA            є
         62892       1F        RRA            є
         62893       1F        RRA            є
         62894       82        ADD A,D        є
         62895       6F        LD L,A         є
         62896   3AD0F5        LD A,(F5D0)    ;Параметр v
         62899       47        LD B,A         ;становится параметром
         62900       C5 LOOP_V PUSH BC        ;цикла и сохраняется на
         62901       E5        PUSH HL        ;стеке вместе с адресом.
         62902   3AD1F5        LD A,(F5D1)    ;Параметр h становится
         62905       47        LD B,A         ;параметром цикла.
         62906       7E LOOP_H LD A,(HL)      ;Сняли с экрана атрибуты
                                              ;знакоместа.
         62907     E638        AND 38         ;Оставили включенными
                                              ;только биты, отвечающие
                                              ;за цвет PAPER.
         62909       4F        LD C,A         ;Временно запомнили в "С".
         62910   3ACFF5        LD A,(INK)     ;Параметры c,b,f.
         62913       B1        OR C           ;Наложили их на PAPER.
         62914       77        LD (HL),A      ;Изменили атрибуты.
         62915       23        INC HL         ;Следующее знакоместо.
         62916     10F4        DJNZ LOOP_H    ;Конец цикла по горизон-
                                              ;тали.
         62918       E1        POP HL         ;Адрес начала ряда.
         62919   012000        LD BC,0020     ;Переход на
         62922       09        ADD HL,BC      ;следующий ряд.
         62923       C1        POP BC         ;Параметр цикла по v.
         62924     10E6        DJNZ LOOP_V    ;Конец цикла по v.
         62926       C9        RET            ;Выход.
         62927       00 INK    DEFB 00        ;Атрибуты
         62928     0000 PARAM  DEFW 0000      ;Параметры v и h.
         62930     0000 COORD  DEFW 0000      ;Параметры y и x.

                   3.4. Окрашивание заданного окна цветом PAPER.

              Процедура  работает  совершенно  аналогично предыдущей, за
         исключением того, что вместо цвета INK, в окне  устанавливается
         заданный цвет PAPER. Параметры  окна выставляются  в  БЕЙСИКе с
         помощью пользовательской   функции FN c(x,y,h,v,c,b,f). Началь-
         ным  адресом взят для   примера адрес 62600, длина процедуры  -
         139 байтов  и еще  пять байтов  в   конце отведены для хранения
         рабочих переменных. Список параметров тот же, что и в  предыду-
         щей процедуре (см.с. 116), единственное отличие состоит в  том,
         что параметр "c" содержит информацию о цвете PAPER (от 0 до 7),
         а не INK, как было ранее.

              Эта процедура также может обслуживать весь экран - все  24
         строки, а не только 22 строки основной его части.

                    10 REM *** Загрузчик машинного кода
                    20 LET adr=62600: LET long=145: LET z=0
                    30 FOR i=0 TO long-1: READ a
                    40 POKE (adr+i),a: LET z=z+a: NEXT i
                    60 LET z=INT (((z/long)-INT (z/long))*long)
                    70 READ a
                    80 IF a<>z THEN PRINT "??": STOP
                    90 REM *** Пример использования процедуры
                   100 DEF FN c(x,y,h,v,c,b,f)=USR 62600
                   110 BORDER 1: PAPER 4: CLS
                   120 FOR i=1 TO 120
                   130 LET x1=INT (RND*17)
                   140 LET y1=INT (RND*10)
                   150 LET h1=INT (RND*16)
                   160 LET v1=INT (RND*15)
                   170 LET c1=INT (RND*7)
                   180 RESTORE FN c(x1,y1,h1,v1,c1,0,0)
                   190 NEXT i: PAUSE 0 : REM пауза до нажатия клавиши.
                   200 REM *** Данные для машинного кода
                   210 DATA  42,  11,  92,   1,   4
                   220 DATA   0,   9,  86,   1,   8
                   230 DATA   0,   9   94, 237,  83
                   240 DATA  22, 245,   9,  86,   9
                   250 DATA  94, 237,  83,  20, 245
                   260 DATA   9, 126, 230,   7, 203
                   270 DATA  39, 203,  39, 203,  39
                   280 DATA  50,  19, 245,   9, 126
                   290 DATA 230,   1,  40,   8,  58
                   300 DATA  19, 245, 246,  64,  50
                   310 DATA  19, 245,   9, 126, 230
                   320 DATA   1,  40,   8,  58,  19
                   330 DATA 245, 246, 128,  50,  19
                   340 DATA 245, 237,  91,  22, 245
                   350 DATA  58,  20, 245, 254,   0
                   360 DATA 200,  58,  21, 245, 254
                   370 DATA   0, 200, 237,  83,  22
                   380 DATA 245, 123, 230,  24, 203
                   390 DATA  63, 203,  63, 203,  63
                   400 DATA 246,  88, 103, 123, 230
                   410 DATA   7, 183,  31,  31,  31
                   420 DATA  31, 130, 111,  58,  20
                   430 DATA 245,  71, 197, 229,  58
                   440 DATA  21, 245,  71, 126, 230
                   450 DATA   7,  79,  58,  19, 245
                   460 DATA 177, 119,  35,  16, 244
                   470 DATA 225,   1,  32,   0,   9
                   480 DATA 193,  16, 230, 201,   0
                   490 DATA   0,   0,   0,   0,   0
                   500 DATA  12

              Демонстрационная  программа  выполняет  печать   случайных
         цветных окон,  окрашенных цветом  PAPER. Мы  бы хотели обратить
         Ваше особое внимание  на то, что  процедура ЙННННННННННННННННН"
         вызывается не через RANDOMIZE USR, а  через є ЫЯЯЯЯЬ    ЯЫЯ   є
         RESTORE USR. В  чем здесь разница?  С точки є Ы    Ы     Ы    є
         зрения самой процедуры,  ей это все  равно, є ЫЯЯЯЯЬ     Ы    є
         для нее разницы  нет, но при  использовании є Ы    Ы Ь  ЬЫЬ Ь є
         RANDOMIZE USR  возникает косвенный  эффект, ИНННННННННННННННННј
         который состоит в том, что всякий раз, когда компьютер встреча-
         ет оператор RANDOMIZE, он переустанавливает содержимое  систем-
         ной переменной SEED (23670=5C76H), содержащей базовую  величину
         для генерации случайных чисел.  Если в большинстве случаев  нам
         это безразлично,  то здесь  мы используем  случайные числа  для
         того, чтобы задавать параметры окрашиваемого окна (строки 130..
         .170).  Если  бы  на  каждом  шаге  функция RANDOMIZE одинаково
         переинициализировала бы  нам системную  переменную SEED,  то мы
         ничего нового на экране не  увидели бы. Таким образом, если  Вы
         имеете дело со случайными  числами, вычисляемыми через RND,  то
         использовать RANDOMIZE USR нельзя - пользуйтесь по  обстоятель-
         ствам RESTORE USR, PRINT USR и т.п.

              Замечательный  эффект  в  духе  Малевича  и  Мондриана  Вы
         сможете получить, например,  если используете эту  процедуру со
         следующей  БЕЙСИк-программой.  Подобные  приемы  придадут Вашим
         программам неповторимый колорит.

           100 DEF FN c(x,y,h,v,c,b,f)=USR 62600: BORDER 7: PAPER 7: CLS
           110 RANDOMIZE FN c(4,10,1,14,0,0,0)
           120 RANDOMIZE FN c(16,0,1,24,0,0,0)
           130 RANDOMIZE FN c(24,0,1,24,0,0,0)
           140 RANDOMIZE FN c(0,9,32,1,0,0,0)
           150 RANDOMIZE FN c(0,17,32,1,0,0,0)
           160 RANDOMIZE FN c(14,3,18,1,0,0,0)
           170 RANDOMIZE FN c(0,0,16,9,4,1,0)
           180 RANDOMIZE FN c(5,18,11,6,6,1,0)
           190 RANDOMIZE FN c(25,0,7,9,2,1,0)
           195 RANDOMIZE FN c(17,10,7,7,1,1,0): PAUSE 0

                          Дисассемблер программы:

         62600   2A0B5C        LD HL,(5C0BH)  ;См. с.109...111.
         62603   010400        LD BC,0004     ;Сдвиг от DEFADD на 4 бай-
         62606       09        ADD HL,BC      ;та (см. c.109...111 ).
         62607       56        LD D,(HL)      ;Координата x.
         62608   010800        LD BC,0008     ;Сдвиг от DEFADD еще на 8
         62611       09        ADD HL,BC      ;байтов (см.c.109...111).
         62612       5E        LD E,(HL)      ;Координата y.
         62613 ED5316F5        LD(COORD),DE   ;Переброска параметров y
                                              ;и x в адреса 62742,62743.
         62617       09        ADD HL,BC      ;Еще сдвиг на 8 байтов.
         62618       56        LD D,HL        ;Ширина окна.
         62619       09        ADD HL,BC      ;Еще сдвиг на 8 байтов.
         62620       5E        LD E,(HL)      ;Высота окна.
         62621 ED5314F5        LD(PARAM),DE   ;Переброска параметров v
                                              ;и h в адреса 62740,62741.
         62625       09        ADD HL,BC      ;Параметр PAPER помещен в
         62626       7E        LD A,(HL)      ;аккумулятор      00000???
         62627     E607        AND 07         ;Выделение PAPER. 00000???
         62629     CB27        SLA A          ;Сдвиг влево.     0000???0
         62631     CB27        SLA A          ;Сдвиг влево.     000???00
         62633     CB27        SLA A          ;Сдвиг влево.     00???000
         62635   3213F5        LD (PAPER),A   ;
         62638       09        ADD HL,BC      ;Параметр (BRIGHT)
         62639       7E        LD A,(HL)      ;принимается,
         62640     E601        AND 01         ;выделяется,
         62642     2808        JR Z,SKIP_1    ;и, если не равен нулю,
         62644   3A13F5        LD A,(PAPER)   ;то в параметре PAPER
         62647     F640        OR 40          ;включается 6-ой бит
         62649   3213F5        LD (PAPER),A   ;и PAPER сохраняется.
         62652       09 SKIP_1 ADD HL,BC      ;Параметр (FLASH)
         62653       7E        LD A,(HL)      ;принимается,
         62654     E601        AND 01         ;выделяется,
         62656     2808        JR Z,SKIP_2    ;и, если не равен нулю,
         62658   3A13F5        LD A,(PAPER)   ;то в параметре PAPER
         62661     F680        OR 80          ;включается 7-ой бит
         62663   3213F5        LD (PAPER),A   ;и PAPER сохраняется.
         62666 ED5B16F5 SKIP_2 LD DE,(COORD)  ;Координаты x,y.
         62670   3A14F5        LD A,(F514)    ;Высота окна (v).
         62673     FE00        CP 00          ;Проверка высоты на ноль.
         62675       C8        RET Z          ;Выход, если так
         62676   3A15F5        LD A,(F515)    ;Ширина окна (h).
         62679     FE00        CP OO          ;Проверка ширины на ноль.
         62681       C8        RET Z          ;Выход, если так
         62682 ED5322F5        LD (COORD),DE  ;Координаты y,x.
         62686       7B        LD A,E         ¦
         62687     E618        AND 18         ¦ Определение адреса
         62689     CB3F        SRL A          ¦ по координатам.
         62691     CB3F        SRL A          ¦
         62693     CB3F        SRL A          ¦
         62695     F658        OR 58          ¦
         62697       67        LD H,A         ¦
         62698       7B        LD A,E         ¦
         62699     E607        AND 07         ¦
         62701       B7        OR A           ¦
         62702       1F        RRA            ¦
         62703       1F        RRA            ¦
         62704       1F        RRA            ¦
         62705       1F        RRA            ¦
         62706       82        ADD A,D        ¦
         62707       6F        LD L,A         ¦
         62708   3A14F5        LD A,(F514)    ;Параметр v
         62711       47        LD B,A         ;становится параметром
         62712       C5 LOOP_V PUSH BC        ;цикла и сохраняется на
         62713       E5        PUSH HL        ;стеке вместе с адресом.
         62714   3A15F5        LD A,(F515)    ;Параметр h становится
         62717       47        LD B,A         ;параметром цикла.
         62718       7E LOOP_H LD A,(HL)      ;Сняли с экрана атрибуты
                                              ;знакоместа.
         62719     E607        AND 07         ;Оставили включенными
                                              ;только биты, отвечающие
                                              ;за цвет INK.
         62721       4F        LD C,A         ;Временно запомнили в "С".
         62722   3A13F5        LD A,(PAPER)   ;Параметры c,b,f.
         62725       B1        OR C           ;Наложили их на INK.
         62726       77        LD (HL),A      ;Изменили атрибуты в
                                              ;знакоместе.
         62727       23        INC HL         ;Следующее знакоместо.
         62728     10F4        DJNZ LOOP_H    ;Конец цикла по горизон-
                                              ;тали.
         62730       E1        POP HL         ;Адрес начала ряда.
         62731   012000        LD BC,0020     ;Переход на
         62734       09        ADD HL,BC      ;следующий ряд.
         62735       C1        POP BC         ;Параметр цикла по v.
         62736     10E6        DJNZ LOOP_V    ;Конец цикла по v.
         62738       C9        RET            ;Выход.
         62739       00 PAPER  DEFB 00        ;Атрибуты PAPER, BRIGHT,
                                              ;FLASH.
         62740     0000 PARAM  DEFW 0000      ;Параметры v и h.
         62742     0000 COORD  DEFW 0000      ;Параметры y и x.



СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



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

Похожие статьи:
Аторы журнала - ZX-Format No.7
Байки - Crazy Ganfaiter party: Глазами участника.
Розыск - Разыскиваются: CAVEMANIA & NIGHT SHIT...
AD&D - разнообразные монстры для кампании "Драконы Подземелий".
TOP10 - десятка лучших игрушек для Спектрума на 20 марта 1998 года.

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