Демосцена на релейном компьютере

Какой компьютер без демосцены? Обратимся к классике от @Manwe_SandS @frog:

До моего визита на Assembly'99 я каждый pаз удивлялся pезультатам голосования на заpубежных demo party. Мне было непонятно, как столько людей могут отдавать голоса за pаботы состоящие из тупой (я пpошу пpощения, но это именно так) последовательности эффектов — плазмы, туннеля, огня, вpащающегося куба (тоpа) и пpочих подобных вещей, не объединенных никаким сюжетом, не несущими никакой идеи.

То что нужно! Возьмём первый попавшийся релейный компьютер и понаделаем эффектов.

Движущаяся синусоида

ac8c3ee688390520e607647336830ffc.png

Всякие движущиеся кривые встечаются в каждом втором демо. Часто их форма меняется, иногда по кривой бегают буквы. Множество красочных вариантов.

Но функцию синуса не так-то просто посчитать. На восьмибитных машинах быстро рисовать и перерисовывать синусоиду не получится — программе на Spectrum-Бейсике на одну кривую нужно секунд 15:

34eeca4ef9a38719852f4e0824c786f8.png

Даже если оптимизировать вывод на экран и расчёты, всё равно будет слишком медленно для демо. Но выход есть — это использование таблицы заранее посчитанных значений синуса.

88d431eb335851749ff9d10b9b712855.png

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

Для первого способа даже есть готовые генераторы, дающие примерно такой результат:

// Formula: sin(2*pi*t/T) 
const int16_t lut[1024] = {
     0,   201,   402,   603,   804,  1005,  1206,
  1407,  1608,  1809,  2009,  2210,  2410,  2611,
  2811,  3012,  3212,  3412,  3612,  3811,  4011,
  4210,  4410,  4609,  4808,  5007,  5205,  5404,
  ...
}

Вторая часть, которая требует особенного подхода, это рисование синусоиды на экране. Ведь чтобы она двигалась, нужно постоянно обновлять картинку, а пикселей на экране много. Но положение всех точек каждый раз пересчитывать не требуется. Например, если мы хотим устроить скроллинг, то можно просто копировать цвета пикселей справа налево, а заново вычислять лишь самый правый столбец изображения. Скроллинг экрана настолько часто используется (например, в играх), что, к примеру, у Commodore C64 и NES для этого была аппаратная поддержка.

Вот и первый фрагмент нашего релейного демо:

Огонь

Огонь — это эффект, который сделать не очень сложно, а смотрится он красиво.

11423192861da25ed726e3a6241bfb93.png

Алгоритм генерации похож на работу клеточного автомата: цвета каждого следующего «поколения» пикселей вычисляются на основе цветов предыдущего поколения. Начинает гореть огонь конечно снизу: последний ряд пикселей заполняется случайными значениями. Величина, которую хранит пиксель, может обозначать яркость или цвет — от чёрного через красный, оранжевый, жёлтый к белому.

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

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

color[x][y] = color[x][y + 1]

Вот так они будут ещё и затухать:

color[x][y] = color[x][y + 1] ? color[x][y + 1] - 1 : 0

Вот так затухать на случайную величину:

int dec = rand() & 3;
int c = color[x][y + 1];
c -= c >= dec ? dec : c;
color[x][y] = c;

Ну и осталось использовать значения пикселей справа и слева, чтобы пламя не просто поднималось вверх, но и немного колебалось:

int dec = rand() & 3;
int c = color[x][y + 1] * 3 + color[x - 1][y + 1] + color[x + 1][y + 1];
c /= 5;
c -= c >= dec ? dec : c;
color[x][y] = c;

Если теперь применить все эти знания, то получим вот такой результат:

Бегущая строка

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

15d90f4f7e04b63d26477322d6ee1e87.png

Иногда они двигались волнообразно

6287f91640637e3a60d21150fbdf6bb2.png

иногда по какой-то сложной трёхмерной поверхности

87179d0426e42f32fb461ad75cbae132.png

Встречались и несколько бегущих строк одновременно.

Традиционно в бегущей строке передавали приветы друзьям и знакомым. Но так как мы на хабре, то выведем традиционное «Hello, Habr!».

3D-лабиринт

Многие спрашивают, можно ли на релейном компьютере запустить Doom. Конечно можно! Даже на ZX-81 был 3D Monster Maze, а релейный компьютер поновее будет.

3D Monster Maze из 1982 года

3D Monster Maze из 1982 года

В демках трёхмерные лабиринты тоже встречались:

cb5da65e8629aa014b6227b4af81f49f.png

Для представления координат точек в трёхмерном пространстче обычно используются черырёхмерные вектора (x, y, z, 1). Тогда многие преобразования (поворот, сдвиг, …) можно представить с помощью умножения этого вектора на матрицу:

9fcb94050edd6bb010ee091b598a183c.png

Современные процессоры даже включают в себя набор инструкций для ускорения таких расчётов.

535451029e19a3a4845c03b57882a05f.jpg

Но так как такие инструкции были созданы, чтобы сводить программистов с ума, в релейном компьютере их нет. Только просты арифметические и логические команды, только хардкор. Кармак же написал Doom безо всяких MMX, значит и мы справимся:

Вот и всё, ребята

Вроде получилось отличное демо. Ещё и релюхами щёлкает, не то что Second Reality с этими вашими микросхемами.

Страница проекта релейного компьютера: https://dovgalyuk.github.io/Relay/

Эмулятор компьютера: https://github.com/ttxine/RelayEmulator

© Habrahabr.ru