Управляемая градиентная спираль на ассемблере в 256 байт (k29)

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

    Предупреждение: Если вы страдаете приступами эпилепсии — НЕ СМОТРИТЕ.


    В Win7 и Vista работать не будет. Нужна Windows XP/2000/98.

    Скачать исполняемый файл: k29.com в DropBox (256 байт)
    Скачать исходный код: k29.asm в DropBox (Компилировать FASM-ом)

    Клавиши управления:
    1. R,G,B — включение и отключение цветовых компонент
    2. <--,SPACE,--> — менять направление и скорость вращения
    3. UP, DOWN — менять масштаб спирали
    4. 0,1,2,3,4,5,6,7,8,9 — менять число ветвей у спирали
    5. ESC — выход

    Эпилог


    Уже довольно долго эта статья валяется у меня в черновиках. Ещё в черновиках на Blogger-е валялась. И сегодня я решил, что если не допишу её сейчас — это не произойдёт никогда. Дописал, в конце немного оборвал и закончил) Ура!!!

    1. Завязка


    Меня всегда интересовали работы с demoparty, особенно категории исчисляющиеся в сотнях байт. Одно дело писать прогу в 64 кило, используя DirectX/OpenGL, и совсем другое — в 512/256/128 байт, используя видеопамять напрямую и т.д. Тут необходимо знание и понимание ассемблера уже на интуитивном уровне. Необходимо уметь оптимизировать код по объёму, а значит понимать и учитывать все тонкости машинного языка программирования. Мы попробуем сделать что-то подобное. Я никогда раньше не писал на ассемблере, но разобраться в существующем коде получалось. Будем считать, что данная статья ориентирована на новичков в ассемблере вроде меня. Потому не претендую на идеальное решение задачи.

    2. Выбор цели


    Теперь нужно придумать себе задачу и воплотить её. Мне на ум сразу пришла небольшая программа, написанная в школьные годы на языке Pascal. Программа была проста до безобразия (2 экрана кода — 50 строк), но в то же время она доставляла. Программа рисовала в графическом режиме (320x200x256) во весь экран вращающуюся спираль. Были задействованы все 256 цветов, для плавного изменения цвета. Было удивительно, что спираль движется без видимой перерисовки. Это можно было бы объяснить использованием нескольких видеостраниц, если бы не скорость вращения. Очевидно, что для отрисовки спирали необходимы вычисления с вещественными числами, что тоже вносит значительную задержку. Спираль вращалась со скорость 3-5 оборотов в секунду (см. рис. 2.1).


    [ Рис. 2.1. Снимок спирали с тремя «руками» ]

    А вся фишка была в том, что спираль рисовалась всего один раз — при запуске программы. После отрисовки спирали программа циклически сдвигала цвета в палитре, что незамедлительно отображалось на экране. Помимо основной функции программа поддерживала изменение цвета спирали и изменение направление вращения. Всего восемь цветов:
    0 #000000 Чёрный (спираль не видно)
    1 #0000FF Голубой
    2 #00FF00 Ярко-зелёный
    3 #00FFFF Бирюзовый
    4 #FF0000 Красный
    5 #FF00FF Пурпурный
    6 #FFFF00 Желтый
    7 #FFFFFF Белый

    Так как для отображения на экране используется цветовая модель RGB, то эти восемь цветов можно получать, комбинируя соответствующие цветовые компоненты (3 бита данных могут кодировать 8 различных значений). Программа использовала клавиши 'R', 'G' и 'B' для вкючения/отключения соответствующих цветовых компонент.

    Программа была написана на языке Pascal в среде разработки Turbo Pascal 7.0. Некоторые функции программы были реализованы в виде ассемблерных вставок. Например, функция установки RGB-значения конкретному элементу из палитры. Код школьных времен (форматирование изменено чтобы не травмировать ничью психику):

    program P_16_B_4;
    uses
       crt,graph,MUSE_OTH,MT_MAIN;
    const
       koef1=3;{ Количество вихрей }
       koef2=3;{ Плотность вихрей }
    var
       gd,gm,gmx,gmy,i,flag,x0,y0,x,y:integer;
       r,alpha:extended;
       k,int:longint;
       key:char;rr,gg,bb:byte;
       ints:string;
       mas:array[0..255,1..3] of byte;
    BEGIN
       gd:=installuserdriver('SVGA256m.BGI',NIL);gm:=2;
       initgraph(gd,gm,'');
       gmx:=getmaxx;
       gmy:=getmaxy;
    
       flag:=1;k:=1;
       for i:=0 to 255 do
          begin
             setRGBpalette(i,k,k,k);
             mas[i,1]:=k;mas[i,2]:=k;mas[i,3]:=k;
             k:=k+flag;
             if k=63 then flag:=-1 else
             if k=0 then flag:=1;
          end;
       setcolor(63);
       settextstyle(1,horizdir,2);
       settextjustify(centertext,centertext);
       outtextxy(gmx div 2,gmy div 2-textheight('!<06@')*2 div 2,
                 '!<06@ freeware');
       outtextxy(gmx div 2,gmy div 2+textheight('!<06@') div 2,
                 '! ! ! Press "R", "G", "B", " " or "Esc" ! ! !');
    
       x0:=gmx div 2;
       y0:=gmy div 2;
       r:=400;
       repeat
          alpha:=0;
          repeat
             x:=round(x0+r*cos(alpha/180*Pi));
             y:=round(y0-r*sin(alpha/180*Pi));
             putpixel(x,y,round(r*koef2+alpha*256/360*koef1/2) mod 128);
             alpha:=alpha+20/(r+1);
          until alpha>=360;
          if keypressed then halt;
          r:=r-1;
       until r<=0;
    
       k:=1;flag:=-1;rr:=1;gg:=1;bb:=1;int:=0;
       repeat
          str(int SHR 2,ints);
          while byte(ints[0])<4 do insert('0',ints,1);
          if int and 3=0 then
          SAVE_MONITOR((gmx+1) div 2-75,(gmy+1) div 2-75,(gmx+1) div 2+74,
                       (gmy+1) div 2+74,'c:\AVATAR\'+ints+'.bmp');
          if keypressed then
             begin
             key:=readkey;
                if key=' ' then flag:=-flag else
                if upcase(key)='R' then rr:=not(rr) and 1 else
                if upcase(key)='G' then gg:=not(gg) and 1 else
                if upcase(key)='B' then bb:=not(bb) and 1 else
                if key=#27 then break;
             end;
          for i:=0 to 127 do
          setRGBpalette(i,mas[(i+k+512) mod 256,1]*rr,
                          mas[(i+k+512) mod 256,2]*gg,
                          mas[(i+k+512) mod 256,3]*bb);
          inc(k,flag);k:=k mod 256;
          inc(int);
       until false;
       closegraph;
    END.
    


    3. Разработка алгоритма


    Сперва разберёмся в том, как функционирует программа и какие функции нам потребуется написать. Формальное описание алгоритма:

    1) Начальное заполнение палитры следующими значениями: (0,0,0)... (63,63,63)... (0,0,0). Иными словами, на протяжении 256-ти элементов палитры цвет плавно меняется от черного к белому и снова возвращается к черному. В данном графическом режиме поддерживается до 256 цветов, каждый из цветов состоит из трёх цветовых компонент. Каждая из цветовых компонент задаётся шестью битами (число от 0 до 63). Белому цвету соответсвует вектор цветовых компонент (63,63,63), а чёрному соответственно — (0,0,0).

    2) Отрисовка спирали включает в себя проход по всем пикселям экрана и заполнение их данными. Формула спирали достаточно проста — зависит лишь от вектора (пара значений: расстояние и угол), указывающего на конкретный пиксель из центра экрана. Иными словами цвет зависит только от длины вектора и угла вектора с подобранными коэфициентами. Перебирая различные коэффициенты можно получить как различное число «ветвей» у спирали, так и различную степень её закрученности.

    3) Циклический сдвиг палитры на одну позицию. Это и даёт иллюзию вращения спирали. То есть, изменяя 256 элементов цветов, мы получаем сдвиг спирали на 1/(256*k) полного оборота. Где k — количество «ветвей» спирали. Таким образом мы избежали перерисовки всех пикселей экрана для вращения спирали. На самом деле сдвигать мы будем не на «одну» позицию, величина и направление сдвига хранятся в специальной целочисленной переменной. Это позволит нам динамически менять направление и скорость вращения спирали.

    4) Проверка нажатий клавиш. Нажатие клавиш R, G и B ведет к включению, либо отключению закреплённой за каждой из клавиш цветовой компоненты. Нажатие на клавиши «вправо»/«влево» увеличивает/уменьшает значение переменной, которая явным образом используется при сдвиге палитры. Переход на пункт 3.

    4. Реализация алгоритма


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


    [ Рис. 4.1. Блок-схема алгоритма ]

    Прочитав об имеющихся компиляторах языка ассемблер в википедии и книге «Искусство дизассемблирования» Криса Касперски и Евы Рокко, я сделал свой выбор в пользу компилятора FASM. Код буду писать в Notepad++, из него же и буду экспортировать в статью с подсветкой синтаксиса.

    Ну чтож, приступим.

    4.1. Функция первоначального заполнения палитры


    Мы собираемся заполнять палитру следующими значениями: (0,0,0),... (63,63,63),... (0,0,0). Нетрудно посчитать, что их всего 127, для равномерного заполнения всех 256 элементов будем заполнять по 2 одинаковых элемента: (0,0,0), (0,0,0),... (63,63,63), (63,63,63),... (0,0,0), (0,0,0). Запишем алгоритм на формальном языке высокого уровня:

    for (int i = 0; i <= 127; i++)
    {
       setPalette(i, i/2, i/2, i/2);
       setPalette(255-i, i/2, i/2, i/2); 
    }
    

    Теперь ассемблерный код с комментариями:
    A B C D
    A. Сохраняем в стеке и восстанавливаем из стека регистры, которые используются в функции.
    B. Регистр CX пробегает в цикле от 0 до 127 включительно.
    C. Формируем параметры и вызываем функцию setPalette. В AL загружаем индекс цвета, в AH загружаем значение яркости, равное половине индекса.
    D. Меняем индекс на (255-i) используя операцию инверии всех битов и вызывает функцию setPalette.

    4.2. Функция отрисовки спирали



    Подумаем над функцией описания градиентной спирали.
    Функция зависящая только от радиуса даёт градиентные окружности:

    pixel[x][y] = k1*sqrt(x*x + y*y);


    [ Рис. 4.1. Градиентные окружности ]

    Функция зависящая только от угла даёт градиентные лучи из центра:

    pixel[x][y] = k1*arctan(x/y);


    [ Рис. 4.2. Градиентные лучи ]

    Функция же линейно зависящая от радиуса и угла даст нам искомую градиентную спираль:
    pixel[x][y] = k1*sqrt(x*x + y*y) + k2*k3*arctan(x/y));


    [ Рис. 4.3. Градиентная спираль ]

    Необходимо лишь подобрать необходимые коэффициенты, для 360-тиградусной правильной отрисовки спирали. Коэффициент k1 влияет лишь на степень закрученности спирали. Для правильного заполнения 360-ти градусов выберем коэффициент k3 таким:

    k3 = 128 / 3.1415927;


    [ Рис. 4.4. Правильная 360-тиградусная градиентная спираль ]

    Коэффициент k2 будет принимать целочисленные значения: 1, 2, 3, 4... Меняя этот кофициент, мы получаем соответствующее число ветвей у спирали. Примеры градиентных спиралей при k2 равном единице, двум и пяти представлены на рис. 4.5, 4.6 и 4.7:


    [ Рис. 4.5. Спираль с одной ветвью ]


    [ Рис. 4.6. Спираль с двумя ветвями ]


    [ Рис. 4.7. Спираль с пятью ветвями ]

    Код отрисовки спирали на псевдо-языке:
    (Без учёта возможных ошибок, в т.ч. деления на ноль)

    for (int y = 0; y < 200; y++)
    for (int x = 0; x < 320; x++)
    {
       y -= 100;
       x -= 160;
       int color = k1*sqrt(x*x + y*y) + k2*128/3.1415927*arctan(x/y);
       y += 100;
       x += 160;
       pixel[x][y] = color;
    }
    


    Теперь реализуем алгоритм на ассемблере.

    A B C D E
    A. Сохраняем в стеке и восстанавливаем из стека регистры, которые используются в функции.
    B. Регистр AX пробегает в цикле от 0 до 199 включительно.
    C. Регистр BX пробегает в цикле от 0 до 319 включительно.
    D. Сохраняем AX и BX в стеке. Выравниваем координаты центра спирали на экране, для разрешения 320x200 сдвигаем центр на середину — (160, 100). Восстанавливаем AX и BX из стека.
    E. Возводим AX в квадрат, меняем местами значение регистров AX и BX, ещё раз возводим AX в квадрат. Имеем в регистрах AX и BX квадраты координат. Складываем значения регистров и загружаем результат в DX.

    Вычислением корня вполне можно пожертвовать в пользу уменьшения размера кода приложения. Хорошо бы сохранить в стеке и восстановить обратно регистры AX и BX при вычислении длинны вектора:

    push ax
    push bx
    
    ; dx = ax^2 + bx^2
    mul ax, ax
    xchg ax, bx
    mul ax, ax
    add ax, bx
    mov dx, ax
    
    pop bx
    pop ax
    

    Теперь код, вычисляющий акртангенс угла по заданным sin и cos:

    ; Вычисляем арктангенс угла * k2
    ; dx += arctan(alpha * k2)
    mov   [cos], ax
    mov   [sin], bx
    finit
    fild  word [cos]
    fild  word [sin]
    fpatan
    fimul word [k2]
    fimul word [glad1]
    fidiv word [glad2]
    fist  word [tmp]
    add   dx, [tmp] 
    


    4.3. Проверка нажатий клавиш



    ; Проверка на нажатие клавиши
    mov  ah, 0Bh ; AX := 0B00h
    int  21h
    cmp  al, 0ffh
    
    jmp_loop_pal_exit:
    jne  loop_pal_out
    
    ; Получаем какое именно нажатие
    mov  ah, 08h
    int  21h
    
    
    label_push_space:
        cmp  al, ' '
        jne  label_push_left
        mov  ch, 0
    
    label_push_left:
        cmp  al, 75
        jne  label_push_right
        dec  ch
    
    .......
    


    Думаю код уже всех достал)) Вот где он лежит целиком: http://codepad.org/mEDX1Z2X

    Ещё уменьшить объём кода можно, убрав лишние клавиши управления. Я думаю, если выкинуть всё управление можно легко уложится в 128 байт. Но без управления не так интересно.
    Share post

    Comments 109

      +6
      IT-иллюзионисты вокруг нас! =)
        +2
        Шикарно!
          +1
          Когда в первый раз смотрел, испугался, подумал что это у меня глаза стали резко цвета менять)
          А так ничего, интересная реализация.
            +20
            Не, круто конечно. Но вот если бы ты это перебил…
              +6
              Да давайте сразу вспоминать известные демки типа Heaven7, Chaos Theory и ещё был один примечательный 3д-экшн, забыл название, на 64 или 128кб, не помню точно
              • UFO just landed and posted this here
                  +3
                  96кбайт
                    +1
                    точно
                  +8
                  Причём тут они, там от 64кб. Тут то тоже 256b.
                    0
                    А можно ссылку на все 64кбайтные творения?
                      +2
                      pouet.net/prodlist.php?type[]=64k&platform[]=Windows&order=&x=31&y=6&page=1&order=
                        0
                        А не подскажете как видео добавить к своей демке? www.pouet.net/prod.php?which=57148
                          +1
                          демки замечательно идут под вайном на линухе. юпии
                          0
                          Самые классные тут в посте есть и в комментариях.
                        0
                        Ну я как бы предупредил, что в ассемблере — новичок)
                          +1
                          А я серьёзно написал, что здорово и это. Главное идти дальше :) Может ты весь мир сможешь удивить. Как знать.
                          +1
                          О, а еще скринсейвер есть на основе этой демки.
                            +1
                            Ссылку не трудно привести здесь?
                        +1
                        Под XP не работает, в dosbox работает но не очищает экран при выходе.
                          +1
                          Хм, у меня всё нормально (XP SP3)
                            +1
                            Подозреваю, от видюхи зависит.
                            +1
                            У меня оно даже под вайном завелось (да, там есть какой-то простой эмуль доса), о чём вы.
                              +1
                              Под эмулем доса и у меня завелось. Видимо, в видеокарте дело.
                                0
                                А у вас часом не 64-битная ОС?
                                  0
                                  Никоим образом.
                                  Windows XP sp3
                                  Intel celeron E1500 @ 2.20 GHz
                            +12
                            2. Если вы страдаете приступами эпилепсии — НЕ ЗАПУСКАЙТЕ.

                            До запуска был уверен, что со мной всё ОК.
                              +1
                              Пострадал? бедняжка…
                              +12
                              Глубина, глубина, я не твой!
                                +3
                                Уже пробовал, не получается :-(
                                  +1
                                  выйти не получается? попробуйте вернуться домой
                                    +2
                                    Ну так, гоняю по уровням, выход ищу :-(
                                      0
                                      Нестыковочка. Не могу я по _уровням_ гонять, ибо выйти можно в конце уровня. Короче, от этой зелёной красоты совсем моск вскипел :-)
                                +1
                                Отличный четвертый тег =)
                                  +7
                                  >> «Если вы страдаете приступами эпилепсии — НЕ ЗАПУСКАЙТЕ»

                                  Эту фразу лучше писать ПЕРЕД видео роликом, а не после него :)
                                    +2
                                    А что за трек?
                                      0
                                      Там где-то должно быть написано на ютубе. Выбрал бесплатную музыку через сервис звукозамены ютуба.
                                        +1
                                        Brad Sucks — Borderline в какой-то обработке
                                        +1
                                        Что за музыка играет в демке?
                                          +10
                                          Я буду всегда обновлять список комментариев перед отправкой.
                                          Я буду всегда обновлять список комментариев перед отправкой.
                                          Я буду всегда обновлять список комментариев перед отправкой.
                                          Я буду всегда обновлять список комментариев перед отправкой.
                                          Я буду всегда обновлять список комментариев перед отправкой.
                                            +2
                                            Fantastic Vamps — Borderline (Fantastic Vamps: 8-Bit Mix)
                                              0
                                              Пожалуй добавлю к описанию видео на ютубе.
                                            +1
                                            Ммм… любимый «13-й графический», знакомый ещё с MS-DOS.
                                            Палитра (3c8, 3c9). Видеопамять 0xA0000000.
                                              +3
                                              Автор, Вас ниразу не стошнило при написании? :)
                                                +1
                                                На самом деле можно прикольные глюки словить если долго смотреть))
                                                  +5
                                                  Новый вид легальных наркотиков — asm. Если будут массово применяться, могут стать вне закона. :-)
                                                    +3
                                                    petrushka.asm скачать бесплатно
                                                    0
                                                    Есть еще торчковая hypnoice.com от Арви Хэккера. 128байт тоже. Через пару минут втыкания в нее начинает неслабо глючить. Стены волнами идут и прочие эффекты.
                                                  +2
                                                  есть еще куда оптимизировать на самом деле.
                                                  можно ужать еще как минимум на 2-3 десятка байт
                                                    0
                                                    Я ужимал до 205 байт, потом добавил управление ± ZOOM на кнопки UP и DOWN и вес стал 234. Добавил в конце байты подписи до 256 байт. Вот так)
                                                    0
                                                    Не завелось…
                                                    Microsoft Windows XP [Version 5.1.2600] SP3
                                                    ---------------------------
                                                    16 bit MS-DOS Subsystem
                                                    ---------------------------
                                                    C:\DOCUME~1\SZELEN~1\Desktop\k29.com
                                                    The NTVDM CPU has encountered an illegal instruction.
                                                    CS:c000 IP:dede OP:ff ff ff ff ff Choose 'Close' to terminate the application.
                                                    ---------------------------
                                                    Close Ignore
                                                    ---------------------------
                                                      0
                                                      Я такое видел пару раз на сборках ZverXP. У вас она стоит?
                                                        –1
                                                        у меня зверь стоит и все работает
                                                          +1
                                                          Значит просто не та версия файла NTVDM.exe
                                                          0
                                                          OEM
                                                            0
                                                            Вот значит в чём дело. Может кастрированный NTVDM…
                                                          0
                                                          NTVDM.exe — Windows NT Virtual DOS Machine.
                                                          По идее у вас какая то версия этого файла не та…
                                                          Поищу пока с чем это может быть ещё связано.
                                                            0
                                                            Попробуйте скачать вот это обновление: www.microsoft.com/technet/security/bulletin/ms04-032.mspx
                                                            +4
                                                            Можно ужать на четверть, от 100h байт — включая сигнатуру в конце — до 0C0h байт.
                                                            Код длинный, поэтому ссылка: pastebin.com/2CXf8EWJ
                                                              0
                                                              Напишите пожалуйста номера строк в которых произвели модификацию.
                                                                +4
                                                                Изменений много, и некоторые не сводятся к изменениям в отдельных строках. Я, пожалуй, отвечу выводом diff, он всё-таки короче всей программы:
                                                                
                                                                4d3
                                                                < ; [106h] == 0
                                                                7,8c6
                                                                <     mov si, 100
                                                                <     mov di, RRR
                                                                ---
                                                                >     mov di, kruch
                                                                21,22c19,20
                                                                <         mov ax, 0A000h
                                                                <         mov es, ax
                                                                ---
                                                                >         push 0A000h
                                                                >         pop es
                                                                25c23
                                                                <         mov ax, si
                                                                ---
                                                                >         mov ax, 100
                                                                31,33c29,30
                                                                <                 
                                                                <                 pusha
                                                                <                     mul  ax
                                                                ---
                                                                >                 push ax cx
                                                                >                     imul ax
                                                                35c32
                                                                <                     mul  ax
                                                                ---
                                                                >                     imul ax
                                                                37,42c34,36
                                                                <                     xor  dx, dx
                                                                <                     mov  bx, [kruch] ;mov  bx, 40    ; K1 = 40
                                                                <                     div  bx
                                                                <                     mov  bx, sp
                                                                <                     mov  word [bx+10], ax
                                                                <                 popa
                                                                ---
                                                                >                     div  word [di]
                                                                >                     push ax
                                                                >                 mov si,sp
                                                                47,50c41,42
                                                                <                 mov   word [si], ax    ; COS
                                                                <                 fild  word [si]
                                                                <                 mov   word [si], cx    ; SIN
                                                                <                 fild  word [si]
                                                                ---
                                                                >                 fild  word [si+4]      ; COS
                                                                >                 fild  word [si+2]      ; SIN
                                                                52,55c44,49
                                                                <                 fimul word [vnum]
                                                                <                 fmul  dword [glad]
                                                                <                 fist  word [si]
                                                                <                 add   dx, [si]
                                                                ---
                                                                >                 fimul word [di+vnum-kruch]
                                                                >                 fmul  dword [di+glad-kruch]
                                                                >                 fiadd word [si]
                                                                >                 fist word [si]
                                                                >                 pop  dx
                                                                >                 pop cx ax
                                                                94d87
                                                                <                 add  al, cl ; + ??????
                                                                102a96
                                                                >                 add  al, cl ; + ??????
                                                                108d101
                                                                <                     mov bx, di
                                                                112c105
                                                                <                         and al, [bx]
                                                                ---
                                                                >                         and al, byte [di+RRR-kruch]
                                                                114c107
                                                                <                         inc bx
                                                                ---
                                                                >                         inc di
                                                                121,123c114
                                                                <                 sub  al, cl ; - ??????
                                                                <             
                                                                <                 inc  al
                                                                ---
                                                                >                 inc al
                                                                157c148
                                                                <             dec  [kruch]
                                                                ---
                                                                >             dec  word [di]
                                                                159c150,151
                                                                <             inc  [kruch]
                                                                ---
                                                                >             inc_kruch_paint_me:
                                                                >             inc  word [di]
                                                                165,167c157
                                                                <             jne  label_push_R
                                                                <             inc  [kruch]
                                                                <             jmp  paint
                                                                ---
                                                                >             je   inc_kruch_paint_me
                                                                172c162
                                                                <             not  byte [di]
                                                                ---
                                                                >             not  byte [di+RRR-kruch]
                                                                177c167
                                                                <             not  byte [di+1]
                                                                ---
                                                                >             not  byte [di+GGG-kruch]
                                                                182c172
                                                                <             not  byte [di+2]
                                                                ---
                                                                >             not  byte [di+BBB-kruch]
                                                                189c179
                                                                <             jmp  paint
                                                                ---
                                                                >             jmp  paint_me
                                                                205c195
                                                                < sign  db 'Dedicated to my wife 9'
                                                                \ No newline at end of file
                                                                ---
                                                                > ;sign  db 'Dedicated to my wife 9'
                                                                
                                                                  +1
                                                                  понял, я почему-то не использовал регистры si и di. Вы их использовали di вместо RRR,GGG,BBB. регистр si вы использовали вместо [106h]. Не понял почему вы заменили 47,50c41,42.
                                                                    +1
                                                                    Наоборот, Вы использовали di для адресации RRR,GGG,BBB и si для адреса временной переменной сопроцессора. У меня все обращения к глобальным переменным идут через di, кроме одного mov [...],al, где это не имеет смысла, а сам di указывает на наиболее часто используемую переменную.

                                                                    47,50c41,42 — это часть изменения: pusha / запись в сохранённую копию на стеке / popa / операция с ax и cx через временную переменную -> push ax cx / операция с сохранённой копией на стеке / pop cx ax.
                                                                      +1
                                                                      А если исходный код прогнать под оптимизирующим по размеру компиляторе, к примеру? Не будет ли код еще меньше? Плохо, что исходник на Паскале, был бы на Си, можно было бы попробовать, для сравнения.
                                                                        +1
                                                                        Ассемблер транслируется напрямую, я думаю.
                                                                        Это высокоуровневые конструкции в ЯВУ могут быть оптимизированы.
                                                                          +4
                                                                          Очевидно, вы никогда не пробовали на практике сравнивать по размеру ассемблерный и эквивалентный скомпилированный код. Компиляторы по скорости ещё могут сравниться с человеком, а по размеру откровенно сливают — тем более, что сегодня и задачи-то такой не ставится.
                                                                    +1
                                                                    Поправка: указанная версия занимала целых 0D0h байт, но тем не менее на четверть ужать можно. Версия на 191 байт, правда, с использованием одной инструкции, появившейся в i386, и в которой спираль по умолчанию вращается: pastebin.com/eJSVzF5L
                                                                    diff с файлом из поста:
                                                                    
                                                                    7c7,8
                                                                    <     mov si, 100
                                                                    ---
                                                                    >     mov si, 0A000h
                                                                    >     mov es, si
                                                                    8a10
                                                                    >     mov bp, 13 ; kruch
                                                                    18,25c20
                                                                    <     push cx
                                                                    <         
                                                                    <         ; ??????? ES ????????? ?? ???????????
                                                                    <         mov ax, 0A000h
                                                                    <         mov es, ax
                                                                    <        
                                                                    <         mov bh, 0FAh ;mov  bx, 320*200
                                                                    <         mov ax, si
                                                                    ---
                                                                    >         mov bh, 0FAh
                                                                    27,43c22,27
                                                                    <         
                                                                    <             mov cx, 160
                                                                    <             lp2:
                                                                    <                 ; ?????? ? DX ????? ??????? ?? K1
                                                                    <                 
                                                                    <                 pusha
                                                                    <                     mul  ax
                                                                    <                     xchg ax, cx
                                                                    <                     mul  ax
                                                                    <                     add  ax, cx
                                                                    <                     xor  dx, dx
                                                                    <                     mov  bx, [kruch] ;mov  bx, 40    ; K1 = 40
                                                                    <                     div  bx
                                                                    <                     mov  bx, sp
                                                                    <                     mov  word [bx+10], ax
                                                                    <                 popa
                                                                    <                 
                                                                    ---
                                                                    >             mov  ax, bx
                                                                    >             xor  dx, dx
                                                                    >             div  word [_320+di-RRR]
                                                                    >             sub  ax, 100
                                                                    >             sub  dx, 160
                                                                    > 
                                                                    49c33
                                                                    <                 mov   word [si], cx    ; SIN
                                                                    ---
                                                                    >                 mov   word [si], dx    ; SIN
                                                                    52,55c36,45
                                                                    <                 fimul word [vnum]
                                                                    <                 fmul  dword [glad]
                                                                    <                 fist  word [si]
                                                                    <                 add   dx, [si]
                                                                    ---
                                                                    >                 fimul word [vnum+di-RRR]
                                                                    >                 fmul  dword [glad+di-RRR]
                                                                    >                 fistp word [si]
                                                                    > 
                                                                    >                 imul  ax, ax
                                                                    >                 imul  dx, dx
                                                                    >                 add   ax, dx
                                                                    >                 xor   dx, dx
                                                                    >                 div   bp
                                                                    >                 add   ax, [si]
                                                                    59,69c49,50
                                                                    <                 mov  byte [es:bx], dl
                                                                    < 
                                                                    <             dec cx
                                                                    <             cmp cx, -160
                                                                    <             jg  lp2
                                                                    <             
                                                                    <         dec ax
                                                                    <         cmp al, -100
                                                                    <         jg  lp1
                                                                    <             
                                                                    <     pop cx
                                                                    ---
                                                                    >                 mov  byte [es:bx], al
                                                                    >                 jnz  lp1
                                                                    77c58
                                                                    <         add  cl, ch ; [DELTA]
                                                                    ---
                                                                    >         add  ch, cl ; [DELTA]
                                                                    88,92d68
                                                                    <                 cmp al, 0 ; was ah!!
                                                                    <                 jl  no_inv
                                                                    <                 not ah
                                                                    <                 no_inv:
                                                                    <                 
                                                                    94d69
                                                                    <                 add  al, cl ; + ??????
                                                                    102a78
                                                                    >                 add  al, ch ; + ??????
                                                                    108,109d83
                                                                    <                     mov bx, di
                                                                    <                     mov cx, 3
                                                                    112c86
                                                                    <                         and al, [bx]
                                                                    ---
                                                                    >                         and al, [di+bx]
                                                                    115c89
                                                                    <                     loop mmm
                                                                    ---
                                                                    >                         jnp mmm
                                                                    118a93,94
                                                                    >                 xor al, 0xFF
                                                                    >                 js  setColor
                                                                    121,122d96
                                                                    <                 sub  al, cl ; - ??????
                                                                    <             
                                                                    124c98
                                                                    <             jnz  setPalette_loop
                                                                    ---
                                                                    >             jns  setPalette_loop
                                                                    138a113,126
                                                                    >         label_push_down:
                                                                    >             cmp  al, 80
                                                                    >             jne  label_push_up
                                                                    >             dec  bp
                                                                    >             jnz  paint_me
                                                                    >             inc_kruch_paint_me:
                                                                    >             inc  bp
                                                                    >             paint_me:
                                                                    >             jmp  paint
                                                                    > 
                                                                    >         label_push_up:
                                                                    >             cmp  al, 72
                                                                    >             je   inc_kruch_paint_me
                                                                    >     
                                                                    142c130
                                                                    <             mov  ch, 0
                                                                    ---
                                                                    >             mov  cl, 0
                                                                    147c135
                                                                    <             dec  ch
                                                                    ---
                                                                    >             dec  cx
                                                                    151,164d138
                                                                    <             jne  label_push_down
                                                                    <             inc  ch
                                                                    <     
                                                                    <         label_push_down:
                                                                    <             cmp  al, 80
                                                                    <             jne  label_push_up
                                                                    <             dec  [kruch]
                                                                    <             jnz  paint_me
                                                                    <             inc  [kruch]
                                                                    <             paint_me:
                                                                    <             jmp  paint
                                                                    < 
                                                                    <         label_push_up:
                                                                    <             cmp  al, 72
                                                                    166,167c140
                                                                    <             inc  [kruch]
                                                                    <             jmp  paint
                                                                    ---
                                                                    >             inc  cx
                                                                    171,174c144,145
                                                                    <             jne  label_push_G
                                                                    <             not  byte [di]
                                                                    <             
                                                                    <         label_push_G:
                                                                    ---
                                                                    >             je   change_color
                                                                    >             inc  bx
                                                                    176,179c147,148
                                                                    <             jne  label_push_B
                                                                    <             not  byte [di+1]
                                                                    <             
                                                                    <         label_push_B:
                                                                    ---
                                                                    >             je   change_color
                                                                    >             inc  bx
                                                                    182c151,152
                                                                    <             not  byte [di+2]
                                                                    ---
                                                                    >         change_color:
                                                                    >             not  byte [di+bx]
                                                                    184a155
                                                                    >             xor  bx, bx
                                                                    189c160
                                                                    <             jmp  paint
                                                                    ---
                                                                    >             jmp  paint_me
                                                                    203c174
                                                                    < kruch dw 13
                                                                    ---
                                                                    > _320  dw 320
                                                                    205c176
                                                                    < sign  db 'Dedicated to my wife 9'
                                                                    \ No newline at end of file
                                                                    ---
                                                                    > ;sign  db 'Dedicated to my wife 9'
                                                                    \ No newline at end of file
                                                                    


                                                                    За вычетом сигнатуры получаем экономию в 234 — 191 = 43 байта.
                                                                    В части изменений вы уже разобрались, дополнительно:
                                                                    — есть свободный регистр bp, самую частую переменную выгоднее засунуть туда, тем более что команды inc/dec word [di] двухбайтовые, а новые inc/dec bp однобайтовые; после этой правки звание самой частой переменной восстанавливается за RRR, на которую и указывает di;
                                                                    — двойной цикл по координатам точки (ax,cx) выгоднее заменить одним циклом по bx — тем более что это цикл до нуля, такие проще — а координаты восстанавливать делением;
                                                                    — cl и ch выгоднее переставить, тогда вместо двухбайтовых inc/dec ch можно использовать однобайтовые inc/dec cx; в качестве побочного эффекта при этом спираль начинает вращаться при запуске;
                                                                    — цикл длины 3 можно записать не только как убывающий по cx от 3 до 0, но и как возрастающий по bx от 0 до 3; нетипичные команды jp/jnp проверяют флаг чётности числа бит в младшем байте результата PF, который для 1 и 2 имеет одно значение, а для 3 — другое; поскольку bx=0 от цикла по точкам, это экономит на инициализации; popa благополучно восстанавливает bx=0;
                                                                    — можно убрать отдельные действия для al>=0 и al<0 за счёт «цикла» длины 2 (действия) / xor al, 0xFF / js (начало);
                                                                    — ветку с безусловным переходом назад jmp paint лучше переместить повыше, чтобы jmp стал коротким;
                                                                    — три команды not byte [di+xxx] можно объединить в одну not byte [di+bx]; после неё надо не забыть сбросить bx.
                                                                      0
                                                                      Супер!
                                                                      (поностальгировал по ассемблеру, которым развлекался лет 10-15 назад)
                                                                  +3
                                                                  Наконец-то на хабре что-то стоящее про ASM

                                                                  (старое всё перечитано а новое и простое не так часто, а ух хорошее и вовсе редкость)
                                                                    +2
                                                                    На ЭЛТ мониторе у вас наблюдается некоторое мерцание. (Щас поймал себя на том, что совершенно не в курсе, как обстоят дела с этой проблемой у LCD).

                                                                    Я попробую объяснить, но могу ошибиться, так как давно всё это было :)

                                                                    Это происходит потому, что вы начинаете рисовать не задумываюсь, в какой точки находится луч кинескопа.

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

                                                                    Поэтому писать напрямую в видеопамять не принято, лучше выделить область памяти, рисовать туда, потом ждать сигнала «развертки», и кидать всё в видеопамять одним большим куском.

                                                                    Примерно так:
                                                                    ;выделяем память
                                                                    mov ah,4ah
                                                                    mov bx,1000h
                                                                    int 21h
                                                                    mov ah,48h
                                                                    int 21h
                                                                    jc exit
                                                                    mov word ptr vseg,ax
                                                                    ;обнулим её
                                                                    mov es,ax
                                                                    xor ax,ax
                                                                    xor di,di
                                                                    mov cx,32000
                                                                    rep stosw ;можно использовать stosd

                                                                    ;ваш код

                                                                    mov dx,3DAh ;порт
                                                                    ; цикл ожидания синхронизации c лучём элт
                                                                    sync:
                                                                    in al,dx
                                                                    test al,8h
                                                                    jz sync

                                                                    pusha
                                                                    push ds

                                                                    ; во vseg, понятно у нас как раз лежит указатель на наш буфер
                                                                    mov ax,word ptr vseg
                                                                    mov ds,ax
                                                                    mov ax,0A000h
                                                                    mov es,ax
                                                                    xor si,si
                                                                    xor di,di
                                                                    mov cx,32000
                                                                    rep movsw ;можно использовать movsd
                                                                    pop ds
                                                                    popa
                                                                    ;всё, фрейм отрисован
                                                                      0
                                                                      Пардон, я никоим образом не взаимодействую с лучами кинескопа. Я отрисовываю спираль только 1 раз (ну и при изменении числа рукавов). Для анимации циклически сдвигается палитра. Так что видеопамять тут как бы не причём.
                                                                        0
                                                                        Да, действительно, извиняюсь. Но мерцание, так или иначе, наблюдается, и именно такое, какое бывает при не синхронизированном анимации.

                                                                        По идеё при смене палитры будет должна быть таже самая проблема, но я проверил, ожидание сигнала развертки перед loop_pal_out эффекта не даёт.

                                                                        Помню, что решал проблему, сейчас поробую раскопать исходники. Может быть они еще живы.

                                                                          0
                                                                          Если что получится — ждём результатов тут.
                                                                          Просто мне кажется с этим ничего не поделать…
                                                                            +1
                                                                            угу, я не разобрался с вашим управлением. Влево/вправо нормально всё, но попробуйте все же добавить после loop_pal_out:
                                                                            mov dx,03dah
                                                                            sync:
                                                                            in al,dx
                                                                            test al,8h
                                                                            jz sync

                                                                            анимация по left/light будет плавнее.

                                                                            А то что я имел в виду в начале ветки, это как раз именно то, что я имел в виду :) А именно: я нажимал up/down, а там перерисовка.
                                                                            но там только синхронизацией не поможешь, скорее всего придется делать буфер.

                                                                            И да, тригонометрию в реалтайме считать не тру, посмотрите, возможно можно обойтись заранее расчитаными таблицами?

                                                                            И еще, зачем
                                                                            mov ax, 0A000h
                                                                            mov es, ax

                                                                            стоит после paint:, если es у вас нигде не меняется?
                                                                              0
                                                                              Таблицы -> память -> объём кода.
                                                                              Вычисления в данном случае приоритетней.
                                                                                0
                                                                                У Вас в коде — непаханное поле для оптимизации
                                                                                  0
                                                                                  Ну не скажи… Та версия что я щас выложил без подписи в конце занимает 234 байта. Сомневаюсь что его можно ужать байт на 20-30. В 10 байт я ещё поверю.
                                                                                    0
                                                                                    Кому-то не понравился ваш коммент. Странно выглядит на фоне одних плюсов вокруг.
                                                                                      0
                                                                                      и даже мой плюс не поправил ситуацию
                                                                                        +1
                                                                                        Ну как вариант могу занятся оптимизацией, посмотрим сколько омжно выкрасть — надо только асм поставить
                                                                                          0
                                                                                          Ну я думаю выкрасть получится на особенностях асма, которые я увы не знаю. Какие-нибудь инструкции особые и т.д. По алгоритму оптимизировать я старался как мог.
                                                                                            +1
                                                                                            Сами себе противоречите
                                                                                              0
                                                                                              Ну это же не «поле» для оптимизации))
                                                                                  0
                                                                                  Возможно стоит вытащить
                                                                                  mov ax, 0A000h
                                                                                  mov es, ax

                                                                                  чуть выше.
                                                                                    0
                                                                                    На самом деле изменение размера я добавил совсем недавно. Уже довёл код до 205 байт и бац! Изменение размера увеличило код до 234 байт.
                                                                              +1
                                                                              Зачем выделять память ведь если нужно всего 64к (320х200 байт), в сегмент влезет

                                                                              код примерный

                                                                              lea si, buf
                                                                              ; обнулим её
                                                                              xor ax,ax
                                                                              xor di,di
                                                                              mov cx,32000
                                                                              rep stosw; можно использовать stosd

                                                                              ; ваш код

                                                                              mov dx,3DAh; порт
                                                                              ; цикл ожидания синхронизации c лучём элт
                                                                              sync:
                                                                              in al,dx
                                                                              test al,8h
                                                                              jz sync

                                                                              buf db?
                                                                                +1
                                                                                Старый стал :)
                                                                              +2
                                                                              Развил Вашу идею, правда… еще 11 лет назад.
                                                                              «Overdoze (pseudo x-mode plasma)» — 238 байт (за минусом 7 байт, смотрите первые 7 байт файла)
                                                                              Работа заняла 5 место на «Chaos Construction 2000» в питере, отправлял удаленно через фидо.

                                                                              Кому интересно:

                                                                              Архив работ «256 byte compo» с СС2000 можно скачать здесь
                                                                              Или здесь (но вроде ссылка на скачивание битая)
                                                                                0
                                                                                Скачал посмотрел. Только оно так быстро скачет. Видно что палитрой играет. Жаль давно уже нет нигде 256b compo.
                                                                                +1
                                                                                Я как-то помню треугольник Серпинского рисовал, правда о размере не думал, хотелось просто чтоб «что-то бегало или мерцало» получилось такая штука…
                                                                                cp.people.overclockers.ru/cgi-bin/dl.pl?id=33331&filename=trngl2.tar.bz2
                                                                                  0
                                                                                  Ну нифига себе не думал) А 105 байт всего вышло))
                                                                                    0
                                                                                    Дело в том что моя лень диктует немного другие условия, для меня 105 байт на ASM это не «всего 105 байт» а «нифига себе аж 105 байт», ибо обычно я пишу на других языках, а ASM это теперь только хобби. Причём чаще всего я пишу чаще под Z80 а на х86 только переписываю то что понравилось.
                                                                                  +1
                                                                                  Раз пошла такая пьянка, вот мои 512 байт. Исходники (Tasm) в комплекте.
                                                                                    0
                                                                                    Мне почему-то показалось, что это ракеты)))
                                                                                    Облака по формуле рисовали или битмап?
                                                                                      +1
                                                                                      Если я правильно помню, там генерятся битмапы по несложному алгоритму, а потом они как-то хитро блюряться.
                                                                                    +1
                                                                                    В Win7 и Vista работать не будет
                                                                                    Это потому что не поддерживается полноэкранный режим. Я давно хочу преодолеть это ограничение, уже даже есть наработки. А именно — во всем виноват видеодрайвер.

                                                                                    А пока можно использовать Windows XP mode — это автоматически устанавливаемая Virtual PC для Win7, очень удобно. Только нужно не забыть «Отключить компоненты интеграции» в меню Сервис.

                                                                                      0
                                                                                      Это потому что не поддерживается полноэкранный режим
                                                                                      А еще, возможно потому, что не поддерживаются COM-файлы
                                                                                        0
                                                                                        Кстати на 32-х битной версии вроде работать должно
                                                                                      +1
                                                                                      .model tiny
                                                                                      .code
                                                                                      .386
                                                                                      org 100h

                                                                                      start: mov al,13h
                                                                                      int 10h
                                                                                      mov ax,0A000h
                                                                                      mov ds,ax
                                                                                      mov dx,1
                                                                                      M0: mov cl,40h
                                                                                      M1: push cx
                                                                                      xor cx,cx
                                                                                      mov ax,1010h
                                                                                      int 10h
                                                                                      add dh,dl
                                                                                      inc bx
                                                                                      pop cx
                                                                                      loop M1
                                                                                      neg dl
                                                                                      add dh,dl
                                                                                      cmp bl,0
                                                                                      jnz M0
                                                                                      M2: mov si,1
                                                                                      mov ax,108h
                                                                                      mov bx,154h
                                                                                      mov bp,101h
                                                                                      call proc1
                                                                                      neg si
                                                                                      add bp,7Eh
                                                                                      add bx,ax
                                                                                      call proc1
                                                                                      in al,60h
                                                                                      dec al
                                                                                      jnz M2
                                                                                      mov ax,3h
                                                                                      int 10h
                                                                                      ret

                                                                                      proc1 proc near
                                                                                      pusha
                                                                                      xor cx,cx
                                                                                      mov cl,0C8h
                                                                                      M4: push cx
                                                                                      mov cl,40h
                                                                                      M3: push cx
                                                                                      xor dx,dx
                                                                                      mov al,byte ptr [bx-1]
                                                                                      add dx,ax
                                                                                      mov al,byte ptr [bx+1]
                                                                                      add dx,ax
                                                                                      mov al,byte ptr [bx-140h]
                                                                                      add dx,ax
                                                                                      mov al,byte ptr [bx+140h]
                                                                                      add dx,ax
                                                                                      shr dx,2
                                                                                      inc dl
                                                                                      inc dl
                                                                                      mov byte ptr [bx],dl
                                                                                      add bx,si
                                                                                      pop cx
                                                                                      loop M3
                                                                                      add bx,bp
                                                                                      pop cx
                                                                                      loop M4
                                                                                      popa
                                                                                      ret
                                                                                      ret
                                                                                      proc1 endp
                                                                                      end start


                                                                                      Вот еще красивая вещь. 128байт. Конструктивно банальнейший клеточный автомат. Но благодаря хитрой формы палитре получается чертовски красивая вещь.

                                                                                      dl.dropbox.com/u/12226548/XCOM.ZIP
                                                                                        0
                                                                                        Прикольно.
                                                                                        –1
                                                                                        Интересне всего как ты допетрил до такого:
                                                                                        3) Циклический сдвиг палитры на одну позицию. Это и даёт иллюзию вращения спирали.

                                                                                        Или случайно обнаружил эффект?
                                                                                          0
                                                                                          Для этого спираль и градиентная. Иначе ничего бы не вышло. Без этой идеи не было бы программы))
                                                                                          +2
                                                                                          Я подобных эффектов много обнаружил когда на Win95 сидел (кто знает что такое «logo.sys» тот поймёт) много тогда картинок туда ставил, включая подобные спирали, правда когда появился интернет я прочитал что всё то что я «открыл» уже лет так с 50 как уже открыто =)
                                                                                            0
                                                                                            Даже просмотрев исходники, не могу себя заставить взглянуть на экран – последствия впечатления просмотра скримеров.
                                                                                              +1
                                                                                              Да, коль таки пошла такая пьянка, вставлю свои пять копеек.

                                                                                              Первая в мире демка в 256 Byte со звуком: www.youtube.com/watch?v=veSkQKzjbws

                                                                                              Я, собственно, звук и вставлял. Слабонервным, как обычно, не смотреть — депрессия гарантирована.
                                                                                                0
                                                                                                Вот интересно, какую часть объма занимает звук?
                                                                                                  0
                                                                                                  Очень небольшую, потому что там не семплирование, а прямая работа с MIDI портом. Заявленное на демопатю звуковое оборудование был Gravis Ultra Sound, у него под DOS в полном комплекте драйверов грузились и MIDI драйвера.

                                                                                                  Мне нужно было сделать только переключение инструмента на орган, чтоб мрачнее было, и потом в качестве нот в порт засовывались случайные ноты с разной громкостью и разной длительностью. Вот и все.
                                                                                                0
                                                                                                Если вы страдаете приступами эпилепсии — НЕ ЗАПУСКАЙТЕ.
                                                                                                  0
                                                                                                  Ну да, не хотелось бы чтобы из-за ролика кто-нибудь пострадал :) Даже если вероятность этого 1/1000000 при определенном количестве просмотров ролика — вероятность сыграет против нас…

                                                                                                Only users with full accounts can post comments. Log in, please.