Решил вспомнить счастливое детство и полазить по сайтам демосценеров — с удивлением обнаружил, что многие выкладывают релизы под.. FreeBSD.
FreeBSD — мягко говоря не самая подходящая система для занятия оптимизированной графикой, поэтому наличие такого количества демо целенаправленно создаваемых под эту систему озадачило.
Поскольку я немного понимаю в компьютерах и использую FreeBSD в качестве одной из основных ОС, решил немедленно собрать и запустить самые интересные проекты.
Для непосвященных
Демосцена[1][2][3][4] (англ. demoscene) — киберкультура, зародившаяся в конце 1970-х годов вместе с распространением первых домашних компьютеров. Это направление компьютерного искусства, главной особенностью которого является выстраивание сюжетного видеоряда, создаваемого в реальном времени компьютером, по принципу работы компьютерных игр.
Демосцена это было и есть и будет круто.
Наверное все серьезные игровые движки и все компьютерные спецэффекты были созданы (и делаются поныне) бывшими сценерами:
4players.de reported that "numerous" demo and intro programmers, artists, and musicians were employed in the games industry by 2007. Video game companies with demoscene members on staff included Digital Illusions, Starbreeze, Ascaron,[43] 49Games, Remedy, Techland, Lionhead Studios,[44] Bugbear, Digital Reality, Guerrilla Games, and Akella.[45]
The Tracker music which is part of Demoscene culture could be found in many Video games of the late 1990s and early 2000s, such as the Unreal, Unreal Tournament, Deus Ex, Crusader: No Remorse, One Must Fall: 2097, Jazz Jackrabbit and Uplink.[46]
Словом демосцена это про спецэффекты и преодоление — как впихнуть невпихуемое туда где ему не место, чтобы стало круто и все офигели. И все действительно офигевают. На полном серьезе.
Ниже несколько классических примеров в качестве иллюстрации.
fr-041: debris. by Farbrausch
Все что вы видите на видео делает «программулина» в 177 килобайт. Это почти в 10 раз меньше размера 3.5 дюймовой дискеты, если кто‑то еще помнит такое устройство.
Исходники тоже уже выложены, если кому интересно.
Lifeforce by Andromeda Software Development
Это уже большое демо — целых 26 Мегабайт! Правда это все еще раз в десять меньше вашей обычной сборки очередного корпоративного говнопроекта, но тем не менее.
Также у группы есть свой очень крутой сайт с кучей других красивых демо.
heaven seven by Exceed
И снова 172кб бинарник рисует и поет всю эту красоту.
Craft by lft
Позволю процитировать автора:
Craft is a demo running on its own minimalistic demo platform. The demo platform is based on an ATmega88 microcontroller.
В самом начале видео демонстрируется та самая «own minimalistic demo platform», на которой вся эта красота запускается.
После публикации статьи на ЛОРе, народ подкинул еще пару интересных проектов, которые просто необходимо упомянуть.
Dírojed by Řrřola
32 байта:
echo 'B013CD10C51F380F10276BDBE58A0F0209028FBFFE02483F4BE460FEC875E7C3' | xxd -r -p - dirojed.com
dosbox dirojed.com
Вот так это выглядит в живую:
Hoody by Rgba
4кб приложение генерирует такую красоту:
Это не статичная картинка и не 3D модель — это алгоритмы, чистая математика, тот самый «матан» который вы так не любили все годы в ВУЗе.
Вот тут алгоритм из демо повторен с помощью WebGL:
Ниже детальный пошаговый разбор алгоритма, от самого автора:
Тестовое окружение
Тестовая машина — мой боевой некроноутбук Lenovo T440:
Загружен i915kms, xorg настроен через modesetting:
[alex@cruella ~]$ cat /usr/local/etc/X11/xorg.conf.d/20-intel.conf
Section "Device"
Identifier "Intel Graphics"
Driver "modesetting"
Option "DRI" "true"
EndSection
Все демо по‑умолчанию запускаются в полноэкранном режиме, но я запускал в окне (ключ ‑w для большинства) для создания более драматичных скриншотов.
Planet Hively by Illi Recentes ImperatoreS & Up Rough
Выглядит это демо возможно не так круто:
Но как говорится есть один нюанс, в виде списка поддерживаемых платформ:
#PLATFORM = os4
# PLATFORM = win32
# PLATFORM = linux
# PLATFORM = aros
# PLATFORM = aros64
# PLATFORM = ppc-aros
# PLATFORM = morphos-cross
# PLATFORM = beos
# PLATFORM = ppc-beos-cross
# PLATFORM = gp2x
# PLATFORM = alpha-linux-cross
# PLATFORM = ia64-linux-cross
# PLATFORM = amd64-linux-cross
# PLATFORM = s390-linux-cross
# PLATFORM = s390x-linux-cross
# PLATFORM = arm-linux-cross
# PLATFORM = sparc-linux-cross
# PLATFORM = psp
# PLATFORM = hppa-linux-cross
# PLATFORM = ppc-linux-cross
# PLATFORM = m68k-linux-cross
# PLATFORM = mips-linux-cross
# PLATFORM = mipsel-linux-cross
# PLATFORM = sh3-linux-cross
# PLATFORM = sh4-linux-cross
# PLATFORM = ppc64-linux-cross
# PLATFORM = sparc64-linux-cross
# PLATFORM = avr32-linux-cross
# PLATFORM = bsdi
# PLATFORM = qnx6
# PLATFORM = solaris
# PLATFORM = skyos
# PLATFORM = openserver5
# PLATFORM = openserver6
# PLATFORM = unixware7
# PLATFORM = mint
PLATFORM = i386-freebsd7
# PLATFORM = amd64-freebsd7-cross
# PLATFORM = sparc64-freebsd7-cross
# PLATFORM = ia64-freebsd6-cross
# PLATFORM = alpha-freebsd5-cross
# PLATFORM = riscos-cross
# PLATFORM = hppa-hpux
# PLATFORM = ia64-hpux
# PLATFORM = zaurus-cross
# PLATFORM = syllable
# PLATFORM = netbsd
# PLATFORM = alpha-netbsd4-cross
# PLATFORM = amd64-netbsd4-cross
# PLATFORM = hppa-netbsd4-cross
# PLATFORM = m68k-netbsd4-cross
# PLATFORM = mipseb-netbsd4-cross
# PLATFORM = mipsel-netbsd4-cross
# PLATFORM = ns32k-netbsd2-cross
# PLATFORM = ppc-netbsd4-cross
# PLATFORM = sh3eb-netbsd4-cross
# PLATFORM = sh3le-netbsd4-cross
# PLATFORM = sh5le-netbsd3-cross
# PLATFORM = sparc-netbsd4-cross
# PLATFORM = sparc64-netbsd4-cross
# PLATFORM = vax-netbsd4-cross
# PLATFORM = arm-netbsd4-cross
# PLATFORM = m68010-netbsd4-cross
# PLATFORM = xbox
# PLATFORM = i386-openbsd
# PLATFORM = alpha-openbsd-cross
# PLATFORM = amd64-openbsd-cross
# PLATFORM = arm-openbsd-cross
# PLATFORM = hppa-openbsd-cross
# PLATFORM = ppc-openbsd-cross
# PLATFORM = mips64-openbsd-cross
# PLATFORM = sh4-openbsd-cross
# PLATFORM = sparc64-openbsd-cross
# PLATFORM = m68k-openbsd-cross
# PLATFORM = sparc-openbsd-cross
# PLATFORM = aix
# PLATFORM = irix
# PLATFORM = irix_marq
# PLATFORM = pandora
Если вы думали, что чего-то понимаете в портировании и кроссплатформенности — начинайте искать себе новую работу. Потому я например такого многообразия никогда в жизни не видел, не то чтобы суметь повторить.
Вот так это демо выглядит будучи запущенным на Raspberry Pi:
Исходники и сборка
Исходники выложили относительно недавно, скачать можно вот тут. К сожалению со сборкой есть ряд проблем.
Во-первых авторы забыли выложить часть ресурсов и при запуске демка будет ругаться. Для исправления, нужно вытащить папку tunes из этого pull request и подложить в корень проекта.
Дальше нужно будет в файле makefile раскомментировать строку:
PLATFORM = i386-freebsd7
И заменить gcc на gcc12:
####### DEFAULT SETTINGS HERE #######
CFLAGS = -Wall -O2
LFLAGS =
CC = gcc12
DEBUGLIB =
TARGET = planethively
FASTMATH = -ffast-math
Собирать необходимо с помощью gmake, стандартный make FreeBSD не подойдет.
Написано демо целиком на чистом Си с использованием SDL (для тех платформ где он есть разумеется).
Ниже пара интересных приемов, найденных в исходном коде.
Быстрое вычисление квадратного корня:
static inline int fastsqrt( int n )
{
if( n > 32767 ) return sqrt( n );
return isqrt[n];
}
Генерация белого шума:
void hvl_GenWhiteNoise( int8 *buf, uint32 len )
{
uint32 ays;
ays = 0x41595321;
do {
uint16 ax, bx;
int8 s;
s = ays;
if( ays & 0x100 )
{
s = 0x80;
if( (LONG)(ays & 0xffff) >= 0 )
s = 0x7f;
}
*buf++ = s;
len--;
ays = (ays >> 5) | (ays << 27);
ays = (ays & 0xffffff00) | ((ays & 0xff) ^ 0x9a);
bx = ays;
ays = (ays << 2) | (ays >> 30);
ax = ays;
bx += ax;
ax ^= bx;
ays = (ays & 0xffff0000) | ax;
ays = (ays >> 3) | (ays << 29);
} while( len );
}
Но едем дальше.
Chrysler by Fit & Bandwagon
Motorola Inside 2004, 1е место
Исходный код находится вот тут, несмотря на то что архив аж от 2009го года — все отлично собирается в современном окружении.
Количество поддерживаемых платформ снова вызывает восторг:
Чтоб я так жил, как вы портируете в общем.
Вот так это демо вживую выглядит на моей FreeBSD:
Сборка и исходники
Cобирается это демо также только с помощью gmake, необходимо поправить Makefile, поставив СС=gcc12:
CC = gcc12
CFLAGS = -O2 -ffast-math `sdl-config --cflags`
#LDFLAGS = `sdl-config --libs` -lm
LDFLAGS = `sdl-config --static-libs` -lm
OBJ = data.o kirjaimet2.o kokko.o maf.o main.o mosaic.o pallot.o plasma.o
ratas.o stripes.o video.o cool_mzx/cool_mzx.a
...
Написано все на чистом Си (а вы сомневались?), также с использованием SDL для поддерживаемых платформ. Ниже некоторые интересные моменты в исходниках.
Заданная PI-константа для Амиги:
#ifdef AMIGA
#define M_PI 3.1415927
#endif
Элегантный способ проверить правильность нескольких вызовов подряд:
int readall(void)
{
int val=0;
val+=readfile("data/tehas2.mod",&musakki);
val+=readfile("data/dd.raw",&dd);
val+=readfile("data/na_eka.raw",&na_eka);
val+=readfile("data/na_toka.raw",&na_toka);
val+=readfile("data/onnettomuus.raw",&onnettomuus);
val+=readfile("data/paa.raw",&paa);
val+=readfile("data/siunaus.raw",&siunaus);
val+=readfile("data/ukko.raw",&ukko);
val+=readfile("data/ratas.raw",&ratas);
val+=readfile("data/kooste.raw",&kooste);
val+=readfile("data/chrysler.raw",&chrysler);
return(val);
}
И сам вызов c проверкой:
if(readall()!=0)
{
printf("Problem loading datasn");
return(0);
}
Отображение кадра из видео:
src=frame[no]*40*200;
dst =buffer;
for (y=0; y<AH; y++)
for (x=0; x<(AW/8); x++) {
ip1=bitti_muunnos+video[src]*8;
*dst++ = *ip1++;
*dst++ = *ip1++;
src++;
}
Как говорится удачи разобраться со ссылочной логикой, это именно тот случай когда на трезвую голову понимание достигнуто быть не может.
Hex Pistols by Fit
Motorola Inside 2005, 1е место, релиз на Амиге да.
Вот так выглядит запуск на фоне собственных исходников:
Сборка и исходники
Исходный код можно скачать вот тут.
Для сборки необходимо опять заменить CC=gcc на CC=gcc12 в Makefile, все просто. Написано все снова на чистом Си и SDL (для всех платформ кроме Амиги).
Из интересных приемов, например вот такое чтение RGB цвета и упаковка его в одну переменную с побитовым сдвигом:
/* Background */
if(!strcmp("backcolr",str))
{
fscanf(s,"%d%d%d",&r,&g,&b);
cgm->back=(r<<16)+(g<<8)+b;
}
Faemiyah
Это целая группа, которая стабильно ваяет и выкладывает релизы под FreeBSD. Напрочь отбитые финские товарищи, исходники всех демо доступны по ссылке.
Yog-Sothoth by Faemiyah
2е место на Assembly, 2013
К сожалению это демо у меня так нормально и не заработало, хотя и собралось — что‑то тонкое с видео.
Ghosts of Mars by Faemiyah
4е место на Assembly 2015
Кадр с ней как раз в шапке статьи, благо выглядит максимально эпично:
Сборка и исходники
Исходный код можно скачать вот тут.
Собирается проект уже «по‑современному» — с помощью cmake:
mkdir build
cd build
cmake ..
Запуск:
./ghosts_of_mars -w -r 800x600
Тут указывается оконный режим -w
и разрешение -r 800x600
Исходный код уже на нескольких языках: C, C++ плюс специальный скрипт на Python для минимизации.
Графика все также на SDL, но уже используются шейдеры и Boost.
Все сложнее и серьезнее — ребята идут к успеху
Но проблемы те же, например свой генератор случайных чисел:
/// More random random.
///
/// It's better to discard a few bottom-most bits to achieve better randomness.
///
/// param op Modulator for random.
/// return Random value in range [0, op[.
static int irand(int op)
{
return (dnload_rand() >> 4) % op;
}
Отладочные блоки на макросах по хардкору:
#if 1
{
const float mul = 65535.0f / largest;
for(unsigned ii = 0; (IMAGE_SIDE * IMAGE_SIDE > ii); ++ii)
{
g_image_data[ii] = static_cast<uint16_t>(65535 - g_image_preprocess[ii] * mul);
}
}
#else
{
const float mul = 255.0f / largest;
for(unsigned ii = 0; (IMAGE_SIDE * IMAGE_SIDE > ii); ++ii)
{
g_image_data[ii] = 255 - static_cast<uint8_t>(g_image_preprocess[ii] * mul);
}
}
gfx::image_png_save(std::string("lol.png"), IMAGE_SIDE, IMAGE_SIDE, 8, g_image_data);
#endif
Что такое #if 1:
Only the first block will be processed -— until someone changes the 1 to a 0. Then the other block will be compiled. This is a convenient way to temporary switch blocks of code in and out while testing different algorithms.
Adarkar Wastes by Faemiyah
Instanssi 2018, 1е место
Вот так демо выглядит в работе на моей FreeBSD:
Сборка и исходники
Исходники все там же, сборка и запуск аналогичны предыдущей работе.
Проект реализован на C++, SDL и Boost, плюс появилась маленькая вставка на ассемблере — для синтезатора. И очень много шейдеров.
Ниже опишу несколько интересных решений, найденных в исходном коде. Опять кастомный генератор случайных чисел, но уже другая реализация:
/** BSD random var. */
static bsd_u_long bsd_rand_next = 2;
int bsd_rand(void)
{
/*
* Compute x = (7^5 * x) mod (2^31 - 1)
* without overflowing 31 bits:
* (2^31 - 1) = 127773 * (7^5) + 2836
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
*/
long hi, lo, x;
/* Must be in [1, 0x7ffffffe] range at this point. */
hi = (long)(bsd_rand_next / 127773);
lo = (long)(bsd_rand_next % 127773);
x = 16807 * lo - 2836 * hi;
if (x < 0)
x += 0x7fffffff;
bsd_rand_next = (bsd_u_long)x;
/* Transform to [0, 0x7ffffffd] range. */
return (int)(x - 1);
}
void bsd_srand(bsd_u_int seed)
{
/* Transform to [1, 0x7ffffffe] range. */
bsd_rand_next = (seed % 0x7ffffffe) + 1;
}
Обработка указанного разрешения (ключ -r 800x600 помните?):
/// Parse resolution from string input.
///
/// param op Resolution string.
/// return Tuple of width and height.
boost::tuple<unsigned, unsigned> parse_resolution(const std::string &op)
{
size_t cx = op.find("x");
if(std::string::npos == cx)
{
cx = op.rfind("p");
if((std::string::npos == cx) || (0 >= cx))
{
std::ostringstream sstr;
sstr << "invalid resolution string '" << op << ''';
BOOST_THROW_EXCEPTION(std::runtime_error(sstr.str()));
}
std::string sh = op.substr(0, cx);
unsigned rh = boost::lexical_cast<unsigned>(sh);
unsigned rw = (rh * 16) / 9;
unsigned rem4 = rw % 4;
return boost::make_tuple(rw - rem4, rh);
}
std::string sw = op.substr(0, cx);
std::string sh = op.substr(cx + 1);
return boost::make_tuple(boost::lexical_cast<int>(sw), boost::lexical_cast<int>(sh));
}
Препроцессинг (макросы) в прямо в коде шейдеров:
float i_fov = 1.73;
//float i_fov = 1.0 / tan(60.0 / 180.0 * PI * 0.5);
#if defined(USE_LD)
perspective[0][0] = i_fov / (float(screen_size.x) / float(screen_size.y));
#elif (DISPLAY_MODE == -800) || (DISPLAY_MODE == 800) || (DISPLAY_MODE == -1200) || (DISPLAY_MODE == 1200)
perspective[0][0] = i_fov / 1.6;
#else // Assuming 16/9.
perspective[0][0] = i_fov / 1.78;
#endif
Демосцена умерла?
Наверное заметили, что все описанные в статье проекты достаточно старые?
Если покопаться в сети — окажется, что большая часть сайтов посвященных демосцене находятся в архивном состоянии, фестивали сценеров уже особо не проводятся и так далее.
Словом, может сложиться неприятное ощущение что демосцена умерла. Я вообщем-то тоже так думал, а затем нашел свежее и прекрасное:
Слово автору:
Решил реализовать новую концепцию на БК0011 — рисование картинок под музыку. Надеюсь на продолжение:) Релиз и исходные тексты: https://www.pouet.net/prod.php?which=... Трек: https://zxart.ee/rus/avtory/k/kuvo/ar...
Если кто не знает, вот что такое БК0011:
Так что дух хардкора еще очень даже жив.
P.S.
Это немного отцезурированная и доработанная версия статьи, оригинал которой доступен в нашем блоге.
0x08 Software
Мы небольшая команда ветеранов ИТ‑индустрии, создаем и дорабатываем самое разнообразное программное обеспечение, наш софт автоматизирует бизнес‑процессы на трех континентах, в самых разных отраслях и условиях.
Оживляем давно умершее, чиним никогда не работавшее и создаем невозможное — затем рассказываем об этом в своих статьях.
Автор: alex0x08