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

Практикум по графике в машинных кодах - закрашивание области. Наложение изображений. Увеличение изображения.


                      3.11. Закрашивание области.

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

              Здесь речь идет о том,  что если на экране есть  некоторое
         замкнутое изображение (контур), то закрасить его  установленным
         цветом  INK  -  это  значит  включить  все выключенные пикселы,
         которые внутри  этого контура  могут быть  найдены, оставив без
         изменения ранее включенные.  Может возникнуть вопрос:  "А каким
         же цветом будет  заполнен наш контур?"  - Это зависит  от того,
         какие атрибуты  установлены для  того или  иного знакоместа. То
         есть при включении пикселов на экране они приобретут тот  цвет,
         который ранее соответствовал  параметру INK для  данного знако-
         места.

              Назовем эту программу  FN j(x,y), где  x и y  - абсолютные
         координаты исходной точки,  с которой начнется  заполнение. Ра-
         зумеется x<255, а y<175. Программа работает по методу  "лесного
         пожара". В окресностях исходной точки включаются все невключен-
         ные пикселы (слева, сверху, справа, снизу) и их координаты  за-
         поминаются в специально отведенном для этой цели буфере,  затем
         следует переход к первой из новых включенных точек.  Окрестнос-
         ти новой точки тоже включаются и запоминаются и следует переход
         ко второй включенной точке и т.д.

                             ------------------¬
                             ¦ T   S   O   I   ¦
                             ¦ Q   M   G   C   L-----¬
                             ¦ L   F   B   A   D   J ¦
                             ¦ R   N   H   E   K   P ¦
                             L------------------------
                                  Рис.  18

              Если мы начали работу с  точки A, то включение точек  идет
         так, как показано на рис. 18.

              Важную роль играет в этой процедуре буфер. Он имеет ориги-
         нальную организацию. Вы, очевидно, знаете один из приемов орга-
         низации памяти, называемый стеком. На стек данные закладываются
         сверху и сверху же и снимаются по принципу "последним пришел  -
         первым уйди". Здесь буфер имеет другую организацию -  конвейер-
         ную.  Конвейер тоже, как и стек, заполняется сверху, но опорож-
         няется снизу. Действует  принцип "первым пришел,  первым уйди".
         Главное отличие состоит в  том, что у стека  динамической явля-
         ется только верхняя граница  - она постоянно "дышит"  вверх или
         вниз. Основание стека -  фиксировано и потому для  обслуживания
         стека в программах достаточно  одной переменной - указателя  на
         текущий адрес вершины стека. У конвейера же динамичными  оказы-
         ваются обе границы  - и нижняя  и верхняя, а  потому надо иметь
         две  переменных-указателя.  Зато  они  не "дышат" вверх-вниз, а
         идут в одном направлении - только вверх. Так, при  обслуживании
         точки A буфер будет  иметь вид, показанный на  рис. 19 а  ,  а
         при обслуживании точки  C - вид,  показанный на рис. 19 б.
         -- -- T--------------------XXXX------------------------- - -¬
         ¦     ¦                                               +-----+
         ¦     ¦               ---CONMAX-----------------------+  I  ¦
         ¦     ¦               ¦                               +-----+
         ¦     ¦               ¦                               ¦  H  ¦
         ¦     ¦               ¦                               +-----+
         ¦     ¦               ¦                               ¦  G  ¦
         ¦     ¦               ¦                               +-----+
         ¦     ¦               ¦                               ¦  F  ¦
         +-----+               ¦                               +-----+
         ¦  E  +----------------                               ¦  E  ¦
         +-----+
         ¦  D  ¦                                               ¦  D  ¦
         +-----+
         ¦  C  ¦                ----CONMIN---------------------+  C  ¦
         +-----+                ¦                              +-----+
         ¦  B  ¦                ¦                              ¦  -  ¦
         +-----+                ¦                              +-----+
         ¦  A  +-----------------                              ¦  -  ¦
         L-----+------------------- BUFFER --------------------+------
          Рис.19а                                             Рис.19б

         Каждая клетка на этих рисунках - это два байта памяти, хранящие
         координаты x и y для данной точки. (Клетки F,G,H добавились при
         обслуживании т.B, а клетка I - при обслуживании C).

              Программная  переменная  BUFFER  содержит адрес физической
         нижней границы буфера. Он фиксирован. Переменная CONMIN -  ниж-
         няя граница конвейера. Отсюда берутся координаты очередной  об-
         служиваемой точки. Эта граница - плавающая. Переменная CONMAX -
         верхняя  граница  конвейера.  Сюда  заносятся координаты точек,
         соседних с обслуживаемой в данный момент, если они не включены.
         Эта граница также плавающая (растет вверх). На верхнюю  границу
         буфера указывает адрес XXXX. Его Вы можете задать сами в  стро-
         ках 57779  и 57870.  В конкретном  примере, рассмотренном ниже,
         этот адрес  уже задан  в строках  DATA (мы  были обязаны задать
         хоть что-то, иначе нельзя  было бы получить контрольную  сумму)
         из расчета,  что на  буфер расходуется  1000 байтов,  начиная с
         адреса 57900. В них можно разместить координаты 500 пикселов на
         экране, что конечно же немного, но программа работает так, что
         когда верхняя граница конвейера "дорастает" до физической верх-
         ней границы буфера, она вновь устанавливается на нижнюю  грани-
         цу. Это сделать можно,  поскольку к этому времени  нижняя часть
         буфера уже очищена и  нижняя граница конвейера ушла  вверх (это
         происходит в  строке 57879).  То же  происходит и  когда нижняя
         граница  конвейера  "дорастает"   до  верхней  границы   буфера
         (57788). Таким образом, наш конвейер работает в отведенном  ему
         ограниченном буфере циклически.

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

              Программа  работает  весьма  быстро  и довольно элегантно.
         Кажется, что заполнение идет по всем диагональным направлениям.
         Верхняя и нижняя границы экрана - непроницаемы для  заполнения,
         зато правая  и левая  имеют возможность  работы "с  возвратом".
         Так,  если  заполнение  дошло  до  правого  края экрана, то оно
         продолжится слева и наоборот.

                    10 REM *** Загрузчик машинного кода
                    20 LET adr=57700: LET long=190: 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
                    500 REM ***Данные для машинного кода
                    510 DATA  42,  11,  92,   1,   4
                    520 DATA   0,   9,  86,  14,   8
                    530 DATA   9,  94, 237,  83,  44
                    540 DATA 226, 237,  83,  42, 226
                    550 DATA  33,  44, 226, 229,  35
                    560 DATA  35,  34,  40, 226, 225
                    570 DATA  34,  38, 226,  42,  38
                    580 DATA 226,  94,  35,  86,  21
                    590 DATA 205, 207, 225,  42,  38
                    600 DATA 226,  94,  28,  35,  86
                    610 DATA 205, 207, 225,  42,  38
                    620 DATA 226,  94,  35,  86,  20
                    630 DATA 205, 207, 225,  42,  38
                    640 DATA 226,  94,  29,  35,  86
                    650 DATA 205, 207, 225,  42,  38
                    660 DATA 226,  35,  35, 229,   1
                    670 DATA  76, 229, 167, 237,  66
                    680 DATA  32,   5, 225,  33,  44
                    690 DATA 226, 229, 225,  34,  38
                    700 DATA 226, 237,  75,  40, 226
                    710 DATA 167, 237,  66, 200, 195
                    720 DATA 133, 225, 237,  83,  42
                    730 DATA 226,  62, 175, 147, 216
                    740 DATA  95, 167,  31,  55,  31
                    750 DATA 167,  31, 171, 230, 248
                    760 DATA 171, 103, 122,   7,   7
                    770 DATA   7, 171, 230, 199, 171
                    780 DATA   7,   7, 111, 122, 230
                    790 DATA   7,  71,   4,  62, 254
                    800 DATA  15,  16, 253,   6, 255
                    810 DATA 168,  71, 126, 160, 192
                    820 DATA 126, 176, 119,  42,  40
                    830 DATA 226, 237,  91,  42, 226
                    840 DATA 115,  35, 114,  35, 229
                    850 DATA   1,  76, 229, 167, 237
                    860 DATA  66,  32,   5, 225,  33
                    870 DATA  44, 226, 229, 225,  34
                    880 DATA  40, 226, 201, 193, 195
                    890 DATA  57,   0,   0,   0,   0

                          Дисассемблер программы:
         57700   2A0B5C        LD HL,(5C0BH)  ;См. с. 109...111
         57703   010400        LD BC,0004     ;Сдвиг от DEFADD на 4 бай-
         57706       09        ADD HL,BC      ;та (см. c.109...111).
         57707       56        LD D,(HL)      ;Координата x.
         57708     0E08        LD C,08        ;Сдвиг на
         57710       09        ADD HL,BC      ;восемь байтов.
         57711       5E        LD E,(HL)      ;Координата y.
         57712 ED532CE2        LD(BUFFER),DE  ;Запомнили x,y.
         57716 ED532AE2        LD(TEMPXY),DE  ;Запомнили x,y.
         57720   212CE2        LD HL,E22C     ;Указание на нижнюю гра-
                                              ;ницу буфера.
         57723       E5        PUSH HL        ;Запомнили ее на стеке.
         57724       23        INC HL         ;Инициализация верхней
         57725       23        INC HL         ;границы
         57726   2228E2        LD(CONMAX),HL  ;конвейера.
         57729       E1        POP HL         ;Восстановили нижнюю гра-
         57730   2226E2        LD(CONMIN),HL  ;ницу буфера и выставили в
                                              ;ней нижнюю границу кон-
                                              ;вейера.
         57733   2A26E2 MAIN_L LD HL,(CONMIN) ;Адрес-указатель на теку-
                                              ;щую координату.
         57736       5E        LD E,(HL)      ;Приняли y.
         57737       23        INC HL         ;Переход к x.
         57738       56        LD D,(HL)      ;Приняли x.
         57739       15        DEC D          ;x-1.
         57740   CDCFE1        CALL PLOT      ;Проверяем точку слева
                                              ;(x-1),y.
         57743   2A26E2        LD HL,(CONMIN) ;Адрес-указатель на теку-
                                              ;щую координату.
         57746       5E        LD E,(HL)      ;Приняли y.
         57747       1C        INC E          ;y+1.
         57748       23        INC HL         ;Переход к x.
         57749       56        LD D,(HL)      ;Приняли x.
         57752   CDCFE1        CALL PLOT      ;Проверяем точку вверху
                                              ;x,(y+1).

         57755   2A26E2        LD HL,(CONMIN) ;Адрес-указатель на теку-
                                              ;щую координату.
         57756       5E        LD E,(HL)      ;Приняли y.
         57757       23        INC HL         ;Переход к x.
         57758       56        LD D,(HL)      ;Приняли x.
         57759       14        INC D          ;x+1.
         57760   CDCFE1        CALL PLOT      ;Проверяем точку справа
                                              ;x+1,y.
         57763   2A26E2        LD HL,(CONMIN) ;Адрес-указатель на теку-
                                              ;щую координату.
         57766       5E        LD E,(HL)      ;Приняли y.
         57767       1D        DEC E          ;y-1
         57768       23        INC HL         ;Переход к x.
         57769       56        LD D,(HL)      ;Приняли x.
         57772   CDCFE1        CALL PLOT      ;Проверяем точку внизу
                                              ;x,y-1.
         57775   2A26E2        LD HL,(CONMIN) ;Адрес-указатель на теку-
                                              ;щую координату.
         57776       23        INC HL         ;Переход к следующей пози-
         57777       23        INC HL         ;ции буфера.
         57778       E5        PUSH HL        ;Запомнили ее на стеке.
         57779   01????        LD BC XXXX     ;XXXX - предельный адреc,
                                              ;до которого может разви-
                                              ;ваться буфер - Вы задаете
                                              ;его сами.
         57782       A7        AND A          ;Сброс флагов регистра F.
         57783     ED42        SBC HL,BC      ;Проверка на переполнение
                                              ;буфера.
         57785     2005        JR NZ PASS     ;Обход, если буфер еще не
                                              ;переполняется.
         57787       E1        POP HL         ;Очистка стека.
         57788   212CE2        LD HL,BUFFER   ;Нижняя граница конвейера
                                              ;выставляется в нижнюю
                                              ;границу буфера.
         57791       E5        PUSH HL        ;Запомнили ее на стеке.
         57792       E1 PASS   POP HL         ;Нижняя граница конвейера.
         57793   2226E2        LD(CONMIN),HL  ;Запомнили ее в переменной
         57796 ED4B28E2        LD BC,(CONMAX) ;Вершина конвейера.
         57800       A7        AND A          ;Сброс флагов.
         57801     ED42        SBC HL,BC      ;Проверка не достигла ли
                                              ;нижняя граница конвейера
                                              ;верхнюю.
         57803       C8        RET Z          ;Если да, то конец работы.
         57804   C385E1        JP MAIN_L      ;Возврат в вершину глав-
                                              ;ного цикла.

              Подпрограмма PLOT выполняет  четыре задачи. Во-первых,  по
         координатам точки, выставленным в регистровой паре DE определя-
         ет адрес в дисплейном файле, соответствующий этой точке  (57807
         - 57837). Эти операции делаются совершенно так же, как и в про-
         цедурах FN f() и FN g() и мы их уже разбирали.

              Вторая задача - проверка не включен ли уже пиксел, имеющий
         данную координату и если да, то возврат (57852 - 57854).

              Третья задача - если пиксел не включен, то его надо  вклю-
         чить (57855 - 57857).

              Четвертая задача - включив пиксел, запомнить его координа-
         ты на вершине конвейера и переместить указатель CONMAX на  сле-
         дующую позицию.

         57807 ED532AE2 PLOT   LD (TEMPXY),DE ;Текущие координаты x,y
         57811     3EAF        LD A,0AFH      ;AFH=175 DEC
         57813       93        SUB E          ;Проверка на выход за пре-
         57814       D8        RET C          ;делы экрана по вертикали.
         57815       5F        LD E,A         ;Дополнение y до 175
         57816       A7        AND A          ;Сброс флага переноса.
         57817       1F        RRA            ;Ротация вправо.
         57818       37        SCF            ;Установка флага переноса.
         57819       1F        RRA            ;Ротация вправо.
         57820       37        SCF            ;Установка флага переноса.
         57821       1F        RRA            ;Ротация вправо.
         57822       AB        XOR E          ;Комплексная
         57823     E6F8        AND 0F8H       ;операция замещения
         57825       AB        XOR E          ;битов 0, 1 и 2.
         57826       67        LD H,A         ;Сформировали старший байт
                                              ;адреса в дисплейном файле
         57827       7A        LD A,D         ;Координата x.
         57828       07        RLCA           ;Вращение влево.
         57829       07        RLCA           ;Вращение влево.
         57830       07        RLCA           ;Вращение влево.
         57831       AB        XOR A          ;Операция замещения
         57832     E6C7        AND C7         ;для битов 3,4,5.
         57834       AB        XOR A
         57835       07        RLCA           ;Вращение влево.
         57836       07        RLCA           ;Вращение влево.
         57837       6F        LD L,A         ;Сформировали младший байт
                                              ;адреса в дисплейном файле
         57838       7A        LD A,D         ;Координата x.
         57839     E607        AND 07         ;Маскирование.
         57841       47        LD B,A         ;Инициализация счетчика
         57842       04        INC B          ;оборотов в регистре B.
         57843     3EFE        LD A,0FEH      ;Байт FE=254 интересен
                                              ;тем, что все биты, кро-
                                              ;ме одного, равны едини-
                                              ;це. Вот эту "дырку" мы
                                              ;и вращаем, пока она не
                                              ;встанет на свое место.
         57845       0F AGAIN  RRCA           ;Вращение влево.
         57846     10FD        DJNZ AGAIN     ;Повтор вращения.
         57848     06FF        LD B,0FFH      ;Инверсия, чтобы печать
         57850       A8        XOR B          ;точки была черным по бе-
                                              ;лому, а не наоборот.
         57851       47        LD B,A         ;Запомнили в B
         57852       7E        LD A,(HL)      ;Приняли в аккумулятор то,
                                              ;что уже содержится на
                                              ;экране в нужной линии.
         57853       A0        AND B          ;Логическое сравнение.
         57854       C0        RET NZ         ;Если пиксел в текущей
                                              ;координате уже включен,
                                              ;то возврат в вызывающую
                                              ;программу.
         57855       7E        LD A,(HL)      ;Приняли в аккумулятор то,
                                              ;что уже содержится на
                                              ;экране в нужной линии.
         57856       B0        OR B           ;Включаем требуемый бит.
         57857       77        LD (HL),A      ;Включаем требуемый пиксел
         57858   2A28E2        LD HL,(CONMAX) ;Указатель вершины конв-ра
         57861 ED5B2AE2        LD DE,(TEMPXY) ;Текущие x и y.
         57865       73        LD (HL),E      ;x
         57866       23        INC HL         ;Переход к y.
         57867       72        LD (HL),D      ;y
         57868       23        INC HL         ;Переместили CONMAX
         57869       E5        PUSH HL        ;и запомнили его.
         57870   01????        LD BC,XXXX     ;Верхняя граница буфера.
         57873       A7        AND A          ;Сброс флагов регистра F.
         57874     ED42        SBC HL,BC      ;Проверка заполненности
                                              ;буфера.
         57876     2005        JR NZ,PASS_1   ;Обход, если буфер не
                                              ;заполнен.
         57878       E1        POP HL         ;Очистка стека
         57879   212CE2        LD HL,E22C     ;Если достигнут верхний
                                              ;предел буфера, то верх-
                                              ;нюю границу конвейера
                                              ;выставляем в нижнюю гра-
                                              ;ницу буфера.
         57882       E5        PUSH HL        ;И запоминаем ее.
         57883       E1 PASS_1 POP HL         ;Верхняя граница конв-ра.
         57884   2228E2        LD (CONMAX),HL ;Запомнили ее.
         57887       C9        RET            ;Возврат.
         57894          CONMIN DEFW           ;Нижняя граница конвей-
                                              ;ера.
         57896          CONMAX DEFW           ;Верхняя граница конвей-
                                              ;ера.
         57898          TEMPXY DEFW           ;Переменная для временного
                                              ;хранения координат теку-
                                              ;щей точки при работе про-
                                              ;цедуры PLOT.
         57900          BUFFER DEFW           ;Нижняя граница буфера.

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

              Пример 1. Требует подгрузки процедуры рисования отрезков
                        прямых FN g(x,y,p,q).

                  100  DEF FN g(x,y,p,q)=USR 60700
                  110  DEF FN j(x,y) = USR 57700
                  120  BORDER 1: PAPER 6: INK 2
                  130  CLS
                  140  FOR i=1 TO 12
                  150  LET x1=i*20
                  160  LET y1=174
                  170  LET x2=10+i*20
                  180  LET y2=20
                  190  RANDOMIZE FN g(x1,y1,x2,y2)
                  200  NEXT i
                  210  FOR i=1 TO 12
                  220  LET x1=i*20
                  230  LET y1=174
                  240  LET x2=i*20-10
                  250  LET y2=20
                  260  RANDOMIZE FN g(x1,y1,x2,y2)
                  270  NEXT i
                  280  RANDOMIZE FN g(10,20,130,2)
                  290  RANDOMIZE FN g(250,20,130,2)
                  300  PAUSE 100
                  310  RANDOMIZE FN j(10,5)

              Пример 2. Требует подгрузки процедуры для изображения
                        прямоугольников FN h(x,y,h,v).

                  100  DEF FN h(x,y,h,v)=USR 60400
                  110  DEF FN j(x,y) = USR 57700
                  120  BORDER 2: PAPER 6: INK 2
                  130  CLS
                  140  LET x=140
                  150  FOR j=110 TO 110 STEP -5
                  160  RANDOMIZE FN h(x,j,60,60)
                  170  IF x/10 = INT (x/10) THEN RANDOMIZE FN j(x+1,j+1)
                  180  LET x=x-5
                  190  NEXT j

                      3.12. Наложение изображений.

              Давайте  рассмотрим  команду  OVER  стандартного  БЕЙСИКа.
         Вы никогда не  задумывались над тем,  что эта команда  является
         фактически логической командой?

              В БЕЙСИКе существуют логические команды AND, OR, NOT - вот
         пожалуй и все. Кроме того, при программировании в машинных  ко-
         дах Вам  доступна еще  и команда  XOR -  "Исключающее ИЛИ". Так
         вот, команда OVER 1 при печати на экране фактически  эквивален-
         тна функции XOR.  Действительно, давайте рассмотрим, что делает
         команда A XOR B. В  результате ее действия включаются те  биты,
         которые были  включены либо  в A,  либо в  B, но  если они были
         включены и в  A и в  B, то они  выключаются (в этом  отличие от
         команды OR).

              А что делает команда OVER  1? Практически то же самое,  но
         при печати на экране. Когда Вы накладываете одно изображение на
         другое, включаются  те пикселы,  которые были  включены в одном
         или в другом  изображении, но если  пиксел был включен  и там и
         там, то он выключается. Кстати, это довольно эффективный  метод
         стирания, когда в режиме OVER 1 Вы печатаете некоторое  изобра-
         жение поверх самого себя. Попробуйте для эксперимента:

                      10 PRINT AT 10,12; OVER 1: "SPECTRUM"
                      20 PAUSE 10:
                      30 GO TO 10

              Не правда ли, очень  похоже на действие команды  FLASH, но
         не совсем то же самое?

              В качестве демонстрации  возможности печати изображений  с
         наложением  по  XOR  мы  рассмотрим  программу  для   наложения
         отрезков прямых FN k(x,y,p,q). Здесь x,y - координаты  исходной
         точки, а p,q - координаты конечной точки отрезка  (абсолютные).
         Ограничения на  величину x,y,p,q,  связанные с  размером экрана
         256x176 очевидны.

                    10 REM *** Загрузчик машинного кода
                    20 LET adr=57600: LET long=15: 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
                    500 REM ***Данные для машинного кода
                    510 DATA  62, 168,  50, 223, 237
                    520 DATA 205,  28, 237,  62, 176
                    530 DATA  50, 223, 237, 201,   0
                    540 DATA  13,   0,   0,   0,   0

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

         57600     3EA8        LD A,0A8H      ;A8 - это код операции
                                              ;XOR B.
         57602   32DFED        LD (EDDF),A    ;В процедуре рисования
                                              ;отрезков прямых FN g()
                                              ;по адресу 60895 стоит
                                              ;код операции BO (OR B).
                                              ;Он принудительно включа-
                                              ;ет требуемый пиксел на
                                              ;экране. Заменив его на
                                              ;XOR B мы включаем пиксел,
                                              ;если он был выключен. В
                                              ;противном случае - нао-
                                              ;борот выключаем.
         57605   CD1CED        CALL ED1C      ;Вызов измененной прог-
                                              ;раммы изображения отрез-
                                              ;ков.
         57608     3EB0        LD A,0B0H      ;0B - код операции OR B.
         57610   32DFED        LD (EDDF),A    ;В процедуре FN g() вос-
                                              ;становили то, что там и
                                              ;должно было быть.
         57613       C9        RET            ;Выход из процедуры.

              Эта  маленькая  и  очень  простая процедура показывает нам
         пример отнюдь не  простой операции. Мы только что сделали изме-
         нение машинного кода одной процедуры (FN g()) из другой. Нам  и
         раньше  приходилось  использовать  несколько процедур совместно
         и при этом они  обменивались данными через выделенную  для этой
         цели  ячейку  памяти.   Здесь  же  имеет место прямое изменение
         рабочего кода одной процедуры из другой.  Это уже совсем другой
         стиль программирования.

              В  учебных  целях  надо  сделать  еще  одно дополнение. Мы
         хорошо знаем, что находится в процедуре FN g() по адресу  60895
         и  потому  перед  выходом  из  подпрограммы  восстановили   там
         первоначальное число, равное B0H. Но не всегда мы заранее можем
         точно  знать,  что  там  было.  Поэтому в общем случае положено
         принять  содержимое   модифицируемой  ячейки   памяти,    потом
         сохранить его в какой-либо  переменной или на стеке  (что менее
         надежно) и только после  этого вносить свои изменения.  А перед
         возвратом следует восстановить то, что было нами нарушено.

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

              Пример 1. Требует подгрузки процедуры рисования отрезков
                        прямых FN g(x,y,p,q).

                  100  DEF FN k(x,y,p,q)=USR 57600
                  110  BORDER 0: PAPER 0: INK 3
                  120  CLS
                  130  LET s=1
                  140  LET a=0
                  150  LET ad=s*PI/128
                  160  LET x1=80
                  180  LET y1=88
                  190  FOR c=1 TO 2
                  200  FOR i=0 TO 255 STEP s
                  210  LET x=x1+INT(70*SIN a)
                  220  LET y=y1+INT(70*COS a)
                  230  RANDOMIZE FN k(x,y,x1,y1)
                  240  LET a=a+ad
                  250  NEXT i
                  260  LET x1=x1+96
                  270  NEXT c
                  280  PAUSE 100
                  290  GO TO 110

              Пример 2. Требует подгрузки процедуры рисования отрезков
                        прямых FN g(x,y,p,q).

                  100  DEF FN k(x,y,p,q)=USR 57600
                  110  BORDER 5: PAPER 5: INK 1
                  120  CLS
                  130  LET s=1
                  140  LET a=0
                  150  LET ad=s*PI/128
                  160  LET x1=127
                  180  LET y1=88
                  190  FOR i=0 TO 255 STEP s
                  200  LET x=x1+INT(110*SIN a)
                  200  LET y=y1+INT(70*COS a)
                  210  RANDOMIZE FN k(x,y,x1,y1)
                  220  LET a=a+ad
                  230  NEXT i
                  240  PAUSE 0
                  250  GO TO 110

                          3.13. Увеличение изображений.

              Если Вы работали с графическим редактором ARTSTUDIO, то не
         могли не восхититься изяществом того, как происходит увеличение
         экрана в 2 раза (MAGNIFY X 2).  Теперь Вы можете это сделать  и
         сами. Достигающийся при этом эффект способен оживить очень мно-
         гие программы.

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

              Вместе с  тем, понятно,  что для  процедуры совершенно все
         равно, что ей надо увеличивать, поэтому увеличив изображение  в
         два раза и  получив новый экран,  Вы можете подать  команду еще
         раз и вновь увеличить экран  в два раза. Так можно  увеличивать
         изображение во много раз. Правда, буфер хранящий исходное изоб-
         ражение,- только один и потому возвратиться Вы можете ТОЛЬКО  К
         ПРЕДЫДУЩЕМУ изображению. Так, если Вы выполните увеличение два-
         жды, то есть увеличите рисунок в 4 раза, то возврат вернет  Вас
         к  изображению,  увеличенному  в  2  раза, а исходное будет уже
         утрачено.

              Назовем эту процедуру FN l(x,y,h,v), где:

              x - горизонтальная координата левого верхнего угла "окна"
                  (задается в знакоместах, - x < 32);
              y - вертикальная координата левого верхнего угла "окна"
                  (задается в знакоместах, - y < 22);
              h - размер "окна" по горизонтали (ширина "окна" - задается
                  в знакоместах, - 2h + x < 32);
              v - размер "окна" по вертикали (высота "окна" - задается
                  в знакоместах, - 2v + y < 32);

              Процедура задается командой DEF FN l(x,y,h,v) = USR 56700
         и вызывается командой RANDOMIZE FN l(x,y,h,v).

              Для восстановления исходного изображения, содержащегося  в
         буфере  можно  воспользоваться  точкой  входа  в   подпрограмму
         COPY_D, которая находится по адресу 56957. Задайте функцию  без
         параметров, например  DEF FN  m() =  USR 56957  и когда  хотите
         восстановить  на   экране  исходное   изображение   пользуйтесь
         командой RANDOMIZE FN m().

                    10 REM *** Загрузчик машинного кода
                    20 LET adr=56700: LET long=285: 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
                    500 REM ***Данные для машинного кода
                    510 DATA  42,  11,  92,   1,   4
                    520 DATA   0,   9,  86,  14,   8
                    530 DATA   9,  94, 237,  83, 137
                    540 DATA 222,   9, 126,  50, 140
                    550 DATA 222,   9, 126,  50, 139
                    560 DATA 222,  58, 138, 222,  71
                    570 DATA  58, 140, 222, 128, 230
                    580 DATA 224,  40,   6,  62,  31
                    590 DATA 144,  50, 140, 222,  58
                    600 DATA 137, 222,  71,  58, 139
                    610 DATA 222, 128, 214,  22,  56
                    620 DATA   6,  62,  21, 144,  50
                    630 DATA 139, 222, 237,  91, 137
                    640 DATA 222, 123, 230,  24, 246
                    650 DATA  64, 103, 123, 230,   7
                    660 DATA 183,  31,  31,  31,  31
                    670 DATA 130, 111,  34, 141, 222
                    680 DATA  17,   0,  64, 167, 237
                    690 DATA  82,  17,   0, 118,  25
                    700 DATA  34, 143, 222, 205, 113
                    710 DATA 222,  42, 141, 222, 237
                    720 DATA  91, 143, 222,  58, 139
                    730 DATA 222,  71, 197,   1,   2
                    740 DATA   4, 197, 205,  20, 222
                    750 DATA 193,  16, 249,  42, 141
                    760 DATA 222, 205,  79, 222,  34
                    770 DATA 141, 222,   6,   4,  13
                    780 DATA  32, 235, 237,  91, 143
                    790 DATA 222, 205,  89, 222, 237
                    800 DATA  83, 143, 222, 193,  16
                    810 DATA 217, 201,  58, 140, 222
                    820 DATA  71,  34, 145, 222, 237
                    830 DATA  83, 147, 222, 197, 205
                    840 DATA  54, 222, 193,  16, 249
                    850 DATA  42, 145, 222, 237,  91
                    860 DATA 147, 222, 229, 205,  99
                    870 DATA 222, 225,  36,  36,  20
                    880 DATA 201,  26,   1,   2,   4
                    890 DATA 197, 245, 175, 119, 241
                    900 DATA  23, 245, 203,  22, 241
                    910 DATA 203,  22,  16, 247,  35
                    920 DATA 193,  13,  32, 237,  19
                    930 DATA 201,  62,  32, 133, 111
                    940 DATA 208,  62,   8, 132, 103
                    950 DATA 201,  62,  32, 131,  95
                    960 DATA 208,  62,   8, 130,  87
                    970 DATA 201,  58, 140, 222, 203
                    980 DATA  39,  71, 126,  36, 119
                    990 DATA  37,  35,  16, 249, 201
                   1000 DATA  33,   0,  64,  17,   0
                   1010 DATA 118,   1,   0,  26, 237
                   1020 DATA 176, 201,  33,   0, 118
                   1030 DATA  17,   0,  64,   1,   0
                   1040 DATA  26, 237, 176, 201,   2
                   1050 DATA   2,   5,  10, 130,  72
                   1060 DATA 226, 118,  98,  78, 194
                   1070 DATA 125,   0,   0,   0,   0
                   1080 DATA  38,   0,   0,   0,   0

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

              1. На первом этапе процедура принимает параметры и  сохра-
         няет их в соответствующих ячейках памяти.

         56700   2A0B5C        LD HL,(5C0BH)  ;См. с.109...111
         56703   010400        LD BC,0004     ;Сдвиг от DEFADD на 4 бай-
         56706       09        ADD HL,BC      ;та (см. c.109...111)
         56707       56        LD D,(HL)      ;Координата x.
         56708     0E08        LD C,08        ;Сдвиг на
         56710       09        ADD HL,BC      ;восемь байтов.
         56711       5E        LD E,(HL)      ;Координата y.
         56712 ED5389DE        LD(COORDY),DE  ;Запомнили x,y.
         56716       09        ADD HL,BC      ;Сдвиг на восемь байтов.
         56717       7E        LD A,(HL)      ;Параметр h.
         56718   328CDE        LD (WIDTH),A   ;Запомнили его.
         56721       09        ADD HL,BC      ;Сдвиг на восемь байтов.
         56722       7E        LD A,(HL)      ;Параметр v.
         56723   328BDE        LD (HEIGHT),A  ;Запомнили его.

              2. Второй этап - первичные проверки и настройки.

         56726   3A8ADE        LD A,(COORDX)  ;Координата x.
         56729       47        LD B,A         ;Координата x.
         56730   3A8CDE        LD A,(WIDTH)   ;Ширина окна h.
         56733       80        ADD A,B        ; x+h
         56734     E6E0        AND E0         ;E0H=1110 0000 BIN
                                              ;Результатом этой операции
                                              ;может быть 0 только в том
                                              ;случае, если в аккумуля-
                                              ;торе выключены три стар-
                                              ;ших бита, то есть h<=31
         56736     2806        JR Z,PASS_1    ;В этом случае все O.K. и
                                              ;делаем обход на PASS_1.
         56738     3E1F        LD A,1FH       ;31
         56740       90        SUB B          ;31-x
         56741   328CDE        LD (WIDTH),A   ;hmax=31-x - максимально
                                              ;допустимое значение h.
         56744   3A89DE PASS_1 LD A,(COORDY)  ;y
         56747       47        LD B,A         ;y
         56748   3A8BDE        LD A,(HEIGHT)  ;v
         56751       80        ADD A,B        ;y+v
         56752     D616        SUB 16H        ;Проверка на <22
         56754     3806        JR C,PASS_2    ;Если y меньше 22, то все
                                              ;O.K. и делаем обход.
         56756     3E15        LD A,15H       ;21
         56758       90        SUB B          ;21-y
         56759   328BDE        LD (HEIGHT),A  ;vmax=21-y - вводим макси-
                                              ;мально допустимое значе-
                                              ;ние v.

              3. На третьем этапе по координатам x и y (заданы в  знако-
         местах) определяем  адрес в  дисплейном файле,  соответствующий
         левому верхнему углу выделенного  нами "окна" и помещаем  его в
         регистровую пару  HL и  в программную  переменную ADDR.

         56762 ED5B89DE PASS_2 LD DE,(COORDY) ;x,y
         56766       7B        LD A,E         ;Координата y     000?????
         56767     E618        AND 18H        ;Выделение сег-
                                              ;мента экрана     000??000
         56769     F640        OR 40          ;Указание на
                                              ;дисплейный файл  010??000
         56771       67        LD H,A         ;Выставили H (cм. рис.   )
         56772       7B        LD A,E         ;Координата y     000?????
         56773     E607        AND 07         ;Выделили номер
                                              ;ряда в сегменте  00000???
         56775       B7        OR A           ;Очистили флаг "С"
         56776       1F        RRA            ;Вращение         000000??
         56777       1F        RRA            ;Вращение         ?000000?
         56778       1F        RRA            ;Вращение         ??000000
         56779       1F        RRA            ;Вращение         ???00000
         56780       82        ADD A,D        ;Прибавили номер
                                              ;столбца          ????????
         56781       6F        LD L,A         ;Младший байт адреса в
                                              ;дисплейном файле.
         56782   228DDE        LD (ADDR),HL   ;Запомнили адрес в пере-
                                              ;менной ADDR.

              4. Зная адрес,  с которого начинается  наше "окно" в  дис-
         плейном файле,  мы можем  теперь сохранить  текущее графическое
         изображение в верхних областях   памяти во временном буфере.  В
         качестве примера здесь принят  начальный адрес буфера 7600  H =
         30208 DEC. Но Вы можете поменять его после того  как  программа
         будет уже набрана  (если сделать это  раньше, может не  сойтись

         контрольная  сумма).  О  том,  как это сделать, мы укажем после
         описания процедуры.

              Таким образом, в буфере получается копия исходного изобра-
         жения.

         56785   110040        LD DE 4000     ;Начало дисплейного файла.
         56788       A7        AND A          ;Очистка флага переноса.
         56789     ED52        SBC HL,DE      ;Определили "смещение" ад-
                                              ;реса начала окна относи-
                                              ;тельно начала дисплейного
                                              ;файла.
         56791   110076        LD DE 7600     ;Начало буфера.
         56794       19        ADD HL,DE      ;Прибавив к нему смещение,
                                              ;получим начальный адрес
                                              ;нашего "окна" в копии.
         56795   228FDE        LD (ADDR_1),HL ;Запомнили этот адрес.
         56798   CD71DE        CALL COPYUP    ;Переброска копии вверх.

              5. Теперь, когда у нас есть копия исходного изображения  в
         буфере, мы можем начать строить удвоенное изображение на  экра-
         не, перебрасывая байт за байтом из буфера на экран и  производя
         при этом удвоение его образа как по горизонтали, так и по  вер-
         тикали. Логика работы при этом очень похожа на логику  программ
         FN (d) и FN e(), которые печатали текст символами двойного раз-
         мера. Фактическая разница в том, что там образ брался из  гене-
         ратора шрифта ПЗУ, а здесь образ берется из буфера.
              Сначала  организуется  цикл  по  вертикали  (по  рядам). В
         результате вместо одного  ряда шириной h  исходного изображения
         мы будем иметь 2 ряда шириной 2h на экране.

         56801   2A8DDE        LD HL,(ADDR)   ;адрес в дисп. файле
         56804 ED5B8FDE        LD DE,(ADDR_1) ;адрес в копии
         56808   3A8BDE        LD A,(HEIGHT)  ;v.
         56811       47        LD B,A         ;Подготавливаем цикл по
                                              ;горизонтальным рядам.
                                              ;Количество рядов = v.
         56812       C5 LOOP_1 PUSH BC        ;Вершина цикла по рядам.
         56813   010204        LD BC 0402     ;Подготавливаем еще 2 вло-
                                              ;женных цикла. Внешний -
                                              ;на 2 прохода (C) и внут-
                                              ;ренний на 4 прохода (B).
         56816       C5 LOOP_2 PUSH BC        ;Вершина внутреннего и
                                              ;внешнего вложенных циклов

              Цикл по горизонтали (по столбцам) для данного ряда органи-         зуется в процедуре DOUBLE.

         56817   CD14DE        CALL DOUBLE    ;8 раз вызывается проце-
                                              ;дура DOUBLE.
         56820       C1        POP BC
         56821     10F9        DJNZ LOOP_2    ;Конец внутреннего цикла
                                              ;по B (4 прохода).
         56823   2A8DDE        LD HL,(ADDR)   ;Адрес в дисп.файле.
         56826   CD4FDE        CALL NEW_R     ;Переход к новому ряду.
         56829   228DDE        LD (ADDR),HL   ;Запомнили новый адрес
                                              ;в дисплейном файле.
         56832     0604        LD B,04
         56834       0D        DEC C          ;
         56835     20EB        JR NZ,LOOP_2   ;Конец внешнего цикла
                                              ;по C (2 прохода).
         56837 ED5B8FDE        LD DE,(ADDR_1) ;Установив новый адрес
         56841   CD59DE        CALL NEW_R_1   ;в дисплейном файле, мы
         56844 ED538FDE        LD (ADDR_1),DE ;переходим и к новому
                                              ;адресу в буфере.
         56848       C1        POP BC
         56849     10D9        DJNZ LOOP_1    ;Конец цикла по рядам.
         56851       C9        RET

              Процедура DOUBLE организует  цикл по горизонтали  для дан-
         ного экранного  ряда.   Она вызывает  процедуру DOUB_L, которая
         выполняет цикл по восьми линиям данного знакоместа.

         56852   3A8CDE DOUBLE LD A,(WIDTH)   ;Ширина "окна"
         56855       47        LD B,A         ;Ширина "окна"
         56856   2291DE        LD (ADDR_2),HL ;Временно запомнили адрес
                                              ;в дисплейном файле.
         56859 ED5393DE        LD (ADDR_3),DE ;Временно запомнили адрес
                                              ;в копии дисплейного файла
         56863       C5 LOOP_3 PUSH BC        ;Вершина цикла по ширине
                                              ;"окна".
         56864   CD36DE        CALL DOUB_L    ;Удвоение линии по гори-
                                              ;зонтали.
         56867       C1        POP BC
         56868     10F9        DJNZ LOOP_3    ;Конец цикла по ширине
                                              ;"окна".
         56870   2A91DE        LD HL,(ADDR_2) ;Перед выходом восстано-
         56873 ED5B93DE        LD DE,(ADDR_3) ;вили испорченные при ра-
                                              ;боте процедуры значения
                                              ;в HL и DE.
         56877       E5        PUSH HL

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

         56878   CD63DE        CALL REPEAT    ;Повторение линии.
         56881       E1        POP HL
         56882       24        INC H
         56883       24        INC H
         56884       14        INC D
         56885       C9        RET

              Процедура DOUB_L  выполняет удвоение  одной линии  в одном
         знакоместе. Побитная  раскладка линии  берется сверху  (DE) и с
         удвоением опускается в дисплейный файл (HL).

                 Ее логику работы  мы разобрали на  стр. 132  и здесь не
         будем на ней останавливаться.

         56886       1A DOUB_L LD A,(DE)
         56887   010204        LD BC,0402
         56890       C5 LOOP_4 PUSH BC
         56891       F5        PUSH AF
         56892       AF        XOR A
         56893       77        LD (HL),A
         56894       F1        POP AF
         56895       17 LOOP_5 RLA
         56896       F5        PUSH AF
         56897     CB16        RL (HL)
         56899       F1        POP AF
         56900     CB16        RL (HL)
         56902     10F7        DJNZ LOOP_5
         56904       23        INC HL
         56905       C1        POP BC
         56906       0D        DEC C
         56907     20ED        JR NZ,LOOP_4
         56909       13        INC DE
         56910       C9        RET

              По адресу начала экранного ряда, содержащегося в HL,  про-
         цедура NEW_R  определяет адрес  начала следующего  нижележащего
         ряда. При этом учитывается,  что следующий ряд может  принадле-
         жать другому экранному сегменту.

         56911     3E20 NEW_R  LD A,20H       ;Переход к новому ряду
         56913       85        ADD A,L        ;Проверка на переполнение
         56914       6F        LD L,A         ;экранного сегмента.
         56915       D0        RET NC         ;Если все O.K., то возврат
         56916     3E08        LD A,08        ;В противном случае изме-
                                              ;няется значение в регист-
         56918       84        ADD A,H        ;ре H, т.е. выполняется
         56919       67        LD H,A         ;переход к новому сегменту
         56920       C9        RET            ;Возврат в вызывающую про-
                                              ;цедуру.

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

         56921     3E20 NEW_R_1LD A,20H       ;Переход к новому ряду
         56923       83        ADD A,E        ;Проверка на переполнение
         56924       5F        LD E,A         ;экранного сегмента.
         56925       D0        RET NC         ;Если все O.K., то возврат
         56926     3E08        LD A,08        ;В противном случае изме-
                                              ;няется значение в регист-
         56928       82        ADD A,D        ;ре H, т.е. выполняется
         56929       57        LD D,A         ;переход к новому сегменту
         56930       C9        RET            ;Возврат в вызывающую про-
                                              ;цедуру.

              Процедура REPEAT повторяет на экране текущую линию на один
         пиксел ниже.

         56931   3A8CDE REPEAT LD A,(WIDTH)   ;Ширина "окна".
         56934     CB27        SLA A          ;Удвоенная ширина
         56936       47        LD B,A         ;"окна".
         56937       7E LOOP_6 LD A,(HL)      ;Адрес в дисплейном файле.
         56938       24        INC H          ;Опустились на одну линию
                                              ;ниже.
         56939       77        LD (HL),A      ;Повторили изображение
                                              ;верхней линии.
         56940       25        DEC H          ;Вернулись к верхней линии
         56941       23        INC HL         ;Перешли к следующему зна-
                                              ;коместу.
         56942     10F9        DJNZ LOOP_6    ;Повторяем процесс, пока
                                              ;пройдем всю ширину окна.
         56944       C9        RET            ;Возврат в вызывающую
                                              ;процедуру.

              Процедура COPYUP копирует содержимое дисплейного файла в
         отведенный буфер.

         56945   210040 COPYUP LD HL,4000H    ;Адрес источника - начало
                                              ;дисплейного файла.
         56948   110076        LD DE,7600H    ;Адрес места назначения -
                                              ;30208 (можно изменить).
         56951   01001A        LD BC,1A00H    ;Количество перебрасывемых
                                              ;байтов.
         56954     EDB0        LDIR           ;Команда на переброску.
         56956       C9        RET            ;Выход.

              Процедура COPY_D восстанавливает первоначальное изображе-
         ние из буфера на экран путем копирования вниз.

         56957   210076 COPY_D LD HL,7600H    ;Адрес источника - начало
                                              ;буфера (можно изменить).
         56960   110040        LD DE,4000H    ;Адрес места назначения -
                                              ;начало дисплейного файла.
         56963   01001A        LD BC,1A00H    ;Количество перебрасывемых
                                              ;байтов.
         56966     EDB0        LDIR           ;Команда на переброску.
         56968       C9        RET            ;Выход.

         56969          COORDY DEFB           ;Вертикальная координата
                                              ;левого верхнего угла
                                              ;"окна", подлежащего
                                              ;увеличению.
         56970          COORDX DEFB           ;Горизонтальная координата
                                              ;левого верхнего угла
                                              ;исходного "окна".
         56971          HEIGHT DEFB           ;Высота "окна" (в знако-
                                              ;местах.
         56972          WIDTH  DEFB           ;Ширина "окна" (в знако-
                                              ;местах).
         56973          ADDR   DEFW           ;Адрес в дисплейном фай-
                                              ;ле, соответствующий
                                              ;текущей координате печати
         56975          ADDR_1 DEFW           ;Адрес в буферном фай-
                                              ;ле, соответствующий
                                              ;текущей координате печати
         56977          ADDR_2 DEFW           ;То же, что и ADDR, но для
                                              ;временного хранения во
                                              ;время работы процедуры
                                              ;DOUBLE.

         56979          ADDR_3 DEFW           ;То же, что и ADDR_1, но
                                              ;для временного хранения
                                              ;во время работы
                                              ;процедуры DOUBLE.

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

              Изменения надо внести в ячейки:

                  56792,56793  - в главной процедуре;
                  56949,56950  - в процедуре COPYUP;
                  56958,56959  - в процедуре COPY_D.

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

                  HB = INT (42005/256) = 164

         и младший байт:

                  LB = 42005 - HB*256 = 42005 - 164*256 = 21

              Изменения в коде выполните оператором POKE:

              POKE 56792,19    POKE 56793,164      POKE 56949,19
              POKE 56950,164   POKE 56958,19       POKE 56959,164

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

              1. Если увеличиваемое  изображение - многоцветное,  то Вам
         не  избежать  проблем  с  "клэшингом" атрибутов, ведь процедура
         FN l(x,y,h,v) растягивает в два раза только пиксельное  изобра-
         жение и не трогает атрибутов. Поэтому желательно, чтобы  увели-
         чиваемое изображение было бы монохромным.

              2. Имеет смысл установить цвет PAPER увеличенного  изобра-
         жения. Для этого прежде, чем делать увеличение в два раза,  це-
         лесообразно предварительно  окрасить "удвоенное  окно" заданным
         Вами цветом  PAPER, для  чего можно  воспользоваться процедурой
         FN c(x,y,h,v,c,b,f).

              3. Увеличенное  изображение будет  лучше смотреться,  если
         его выделить из общего поля экрана с помощью прямоугольной рам-
         ки, для чего  после окрашивания в  цвет PAPER можно  воспользо-
         ваться процедурой изображения прямоугольников FN h(x,y,h,v).



СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Demoscene - Deja Vu #08: Demоmаking illness.
Scene - History of making demo "WeeD".
Развитие платформы - новая звуковая карта для Спектрума DMA UltraSound Card.
От редакции - О создании Минского Модемноги Издания.
BBS - список станций BBS ZXNet.

В этот день...   30 апреля