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

Первая моя работа называется Way и написана для платформы Sony Playstation 1 (PSX) на ассемблере MIPS R3000.

Way by Frog (PSX, MIPS R3000)
Way by Frog (PSX, MIPS R3000)

Хотя RISC процессоры обычно не лучший выбор для написания компактного кода, но в случае с PSX это компенсируется способностью GPU аппаратно рисовать примитивы.
По сути, мы просто перечисляем примитивы в специальном формате и потом отправляем этот список (display list) в GPU, предварительно установив графический режим 640x480.

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

sky
    db soil, soil>>8, soil>>16, $8   ; link to next list element, size of current element
    dw $38aa5b00    ; $38 - gradated 4p poly. CCBBGGRR (C - command, b,g,r - color0) $38c4deeb 
    dw $00000000    ; y0  x0 0 0
    dw $30bb5b00    ; color 1  
    dw $0000027f    ; y1  x1 639 0
    dw $30f3dec6    ; color 2    
    dw $01300000    ;  y2  x2 0 304
    dw $30f3dec6    ; color 3 
    dw $0141027f    ; y3  x3 639 321

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

Вот исходник.

Совершенно аналогичным образом устроена и работа "Invitation to CC'2024" (928 байт) - с некоторым закосом под супрематизм, при этом буквы формируются "вырезанием" одних четырёхугольников из других (рисованием их в цвет фона).

CC'2024 Invitation by Frog (PSX, MIPS R3000)
CC'2024 Invitation by Frog (PSX, MIPS R3000)

Несколько сложнее обстоят дела с другой моей работой - Face (646 байт), написанной для платформы Vectrex.

Face by Frog (Vectrex, Motorola 6809)
Face by Frog (Vectrex, Motorola 6809)

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

Лицо состоит из нескольких элементов - брови и границ глаза (прямые линии), зрачка глаза (кривая) и контура лица (две кривых).

С прямыми всё просто - есть подпрограмма BIOS Draw_Line_d. А вот с кривыми - сложно.
Суть подхода в том, что мы вручную запускаем интегрирование - луч начинает перемещаться сверху вниз от текущего своего положения до заданного нами значения Y. В это время мы записываем в канал X разные значения и таким образом заставляем луч смещаться влево (если значения отрицательные) и вправо (если положительные). После записи очередного значения мы или сразу записываем следующее или некоторые время ничего не делаем, предоставляя лучу продолжить движение в прежнем направлении. Это "ничегониделанье" первоначально выглядело как куча NOP'ов после каждого изменения X, причём я приклеил к экрану кусок пергамента с рисунком и подбирал значения в VIDE эмуляторе.

Vide и подбор значений к картинки на приклеенном к монитору пергаменте
Vide и подбор значений к картинки на приклеенном к монитору пергаменте
...
                lda     #30
                sta     <VIA_port_a        	; put X to DAC 

                nop                         ; 2 cycles for each nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop

...

В 1кб при таком подходе не уложишься, поэтому все длинные последовательности nop'ов я свернул в циклы. Причём, сами инструкции подготавливающие и реализующие цикл конечно тоже имеют некую длительность выполнения, что тоже пришлось учитывать, посчитав все такты (ну, примерно):

...
                lda     #30
                sta     <VIA_port_a        	; put X to DAC 

; 10
                ldb    #2                   ; 2 cycles
d6a:            decb                        ; 2 cycles
                bpl     d6a                 ; 3 cycles
...

Вообще, первая мысль которая должна возникать при взгляде на этот код - что там куча повторяющихся кусков и все задержки можно свести в таблички и доставать их оттуда. Увы, любой лишний такт приведёт к продлению рисуемого вектора, поэтому простое решение здесь не сработает. Теоретически можно написать генератор кода - т.е. чтобы программа по данным из таблички воссоздавала нужные последовательности инструкций. К сожалению, у Vectrex-а всего лишь 1кб ОЗУ - упихать наверное можно, но игра в данном случае не стоит свеч (в 1кб и так всё влезло).

Отдельная проблема - наличие в силуэте лица элементов, близких к горизонтальным (возле губ). Дело в том, что луч движется сверху вниз с постоянной скоростью - его нельзя притормозить. Крутизна изгиба определяется исключительно величиной записываемого в X значения. Но больше чем +/- 127 туда, по понятным причинам, записать нельзя.
Можно было бы сделать эти два элемента просто отдельными линиями, но это привело бы либо к видимым нестыковкам концов линии и прилегающей кривой, либо к ярким точкам в местах соединения. В результате я сделал силуэт из четырёх кривых, каждая из которых начинается там, где заканчивается вторая. Тот факт, что интегрирование запускается заново, позволяет лучу с самого начала сегмента двигаться влево (и вправо), таким образом получаем близкие к горизонтальным линии.

Зрачок - просто кусочек кривой.

Летящие справа светящиеся объекты отображаются вызовом подпрограммы BIOS Dot_List, которая рисует векторы с нулевой длиной по списку координат. Подпрограмма вызывается трижды со смещением по горизонтали, при этом после каждого вызова меняется яркость (чтобы создать эффект motion blur).

Текст также выводится подпрограммой BIOS Print_List_hw, что, при таком количестве текста, является весьма неэффективным методом. Однако, в данном случае он оправдан - во-первых с целью экономии байт (вызов стандартной процедуры короче написания своей), во-вторых всё вместе (текст, прямые, кривые) укладывается в 30 тыс тактов процессора, что необходимо чтобы избежать мерцания и других нежелательных эффектов.

Хотя изначально эта работа задумывалась именно как процедурная графика, в процессе вышеописанных развлечений мне пришла в голову мысль, что можно сделать лицо слегка шевелящимся, просто изменяя в некоторых местах значения на которые отклоняется луч и задержки после записи этих значений. Так появилась ещё интро Aniface (820 байт),

Видео не передаёт теплоты и ламовости векторного CRT монитора (да и фото - лишь отдалённо). Увы, тут надо весьма серьёзную видеокамеру (нужен широкий динамический диапазон и высокая светочувствительность) и много времени на подбор параметров съёмки.

Напоследок покажу все работы (других авторов), представленные на данный конкурс фестиваля Chaos Constructions:

Дисквалифицированная работа Rebranding by artёmka // wbcbz7 - работа написана для TIC-80, но по правилам конкурса работы для виртуальных платформ не принимаются

 Rebranding by artёmka // wbcbz7
Rebranding by artёmka // wbcbz7

Шестое место - Ancient Aztec Matrix 128b by g0blinish (125 байт) для Commodore 64 (процессор 6510)

Ancient Aztec Matrix 128b by g0blinish
Ancient Aztec Matrix 128b by g0blinish

Пятое место - моя, уже упомянутая выше, работа Way by Frog //ROi

Четвёртое место - Reptile 1k by g0blinish для ZX Spectrum (процессор z80)

Reptile 1k by g0blinish
Reptile 1k by g0blinish

Третье место - моя, уже упомянутая выше, работа Face by Frog //ROi

Второе место - Teonon by dart / fnm (1022 байта) - единственная из всех, написанная для современной платформы (PC/Windows)

Teonon by dart / fnm
Teonon by dart / fnm

Победитель - работа RTZX by RCL of Virtual Vision Group (983 байта).

RTZX by RCL of Virtual Vision Group
RTZX by RCL of Virtual Vision Group

Как пишет в пояснении к работе сам автор, им реализован честный raytracer для ZX Spectrum 48K (процессор z80). На входе положение камеры и четыре примитива. Работа была написана под впечатлением реализации raytracer'а на Бейсике, в котором рендеринг шёл 17 часов. Конкурсная работа рендерится 43 секунды.

Места определялись голосованием зрителей - интересно, что RTZX победила, т.к. люди, очевидно, смогли оценить сложность реализации raytracer'а на z80 в таком объёме кода.

Все работы можно скачать здесь или здесь.

В целом меня, как одного из организаторов Chaos Constructions, особенно топившего за этот конкурс, весьма порадовали представленные работы - все они (включая дисквалифицированную) весьма достойны.

Комментарии (2)


  1. MasterMentor
    11.09.2024 04:21
    +1

    На СС'24 хороша лекция о ТВ. Конкретно интересна первая её часть о механическом телевидении https://ru.wikipedia.org/wiki/Механическое_телевидение . Её #рекомендую.

    Семинар "Телевидение 90х: монтаж и спецэффекты без компьютера", Тимофей Мокиенко https://www.youtube.com/watch?v=ErZ508N_m88


  1. MasterMentor
    11.09.2024 04:21
    +1

    Teonon by dart / fnm - бесспорно первое место.