unix
March 24, 2023

Демосцена.. на FreeBSD

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

Ghosts of Mars by Faemiyah, на моей домашней FreeBSD.

Кратко для тех кто не знает

Демосцена это было и есть круто. Наверное все топовые игровые движки и все компьютерные спецэффекты были сделаны (и делаются поныне) бывшими сценерами:

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

https://www.pouet.net/prod.php?which=30244

Все что вы видите на видео делает «программулина» в 177 килобайт.

Это почти в 10 раз меньше размера 3.5 дюймовой дискеты, если кто-то еще помнит что сие такое.

Исходники тоже уже выложены, если кому вдруг интересно.

Lifeforce by Andromeda Software Development

https://www.pouet.net/prod.php?which=31571

Это уже большое демо — целых 26 Мегабайт!

Задумайтесь о смысле своей работы, собирая очередной гиговый билд, набитый всяким говном.

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

heaven seven by Exceed

https://www.pouet.net/prod.php?which=5

И снова 172кб бинарник рисует и поет всю эту красоту.

Craft by lft

https://www.pouet.net/prod.php?which=50141

Позволю процитировать:

Craft is a demo running on its own minimalistic demo platform. The demo platform is based on an ATmega88 microcontroller.

В видео в самом начале показывается как выглядит железка, на которой эта

красота запускается.


После выкладывания статьи на ЛОРе, народ подкинул еще пару интересных вещей, которые просто необходимо упомянуть.

Dírojed by Řrřola

32 байта:

echo 'B013CD10C51F380F10276BDBE58A0F0209028FBFFE02483F4BE460FEC875E7C3' | xxd -r -p - dirojed.com
dosbox dirojed.com

Выглядит вот так:

Dosbox это вот.

Hoody by Rgba

4кб бинарник генерирует вот такое:

Это не статичная картинка и не 3D-модель - это алгоритмы.

Чистая математика.

Вот тут алгоритм повторен в WebGL:

А это детальный пошаговый разбор алгоритма, от самого автора:

Учите матан вообщем, матан - сила.

Круто, очень.

Вот тут лежит подборка других крутых демо, для дополнительного просмотра.

Вообщем думаю идею вы поняли.

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

Я к сожалению не дорос до демосцены, не мой уровень, поэтому на этом празднике хардкора — лишь зритель.

FreeBSD и демосцена

Как-то решил я вспомнить счастливое детство и полазить по сайтам сценеров — с удивлением обнаружил, что много кто выкладывает релизы демок под FreeBSD.

FreeBSD — мягко говоря не самая подходящая система для занятия оптимизированной графикой, поэтому это своего рода тоже показатель уровня мастерства и духа сцены: «жги так чтоб все ох#ели».

Вообщем ниже расскажу что из этого удалось собрать и запустить.

Тестовая машина — все тот же боевой некроноут Lenovo T440:

Встроенная графика Intel, 8Гб памяти и FreeBSD 13.1

Загружен 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.

Написано все на чистом Си, с использованием 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 [web] & Bandwagon [web]

Motorola Inside 2004, 1е место

https://www.pouet.net/prod.php?which=12391

Исходник лежит вот тут, несмотря на то что архив от 2009го года — все отлично собирается.

Количество поддерживаемых платформ:

Чтоб я так жил, как вы портируете вообщем.

На моей фре это выглядит вот так:

Сборка и исходники

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 datas\n");
        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 [web]

Motorola Inside 2005, 1е место, релиз на Амиге да.

https://www.pouet.net/prod.php?which=17311

Вот так выглядит запуск на фоне исходников демки:

Сборка и исходники

Исходники можно скачать вот тут. Для сборки надо опять заменить 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 [web] [demozoo] [glöplog]

Это целая группа, которая стабильно ваяет и выкладывает релизы под FreeBSD. Напрочь е#нутые финские товарищи, зацените сколько исходников.

Yog-Sothoth by Faemiyah

2е место на Assembly, 2013

https://www.pouet.net/prod.php?which=61660

К сожалению эта демка у меня так нормально и не заработала, что-то тонкое с видео.

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.

Вообщем все сложнее и серьезнее.

Но проблемы те же — снова кастомный random:

/// 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е место

https://www.pouet.net/prod.php?which=75218

Вот так выглядит на моей FreeBSD:

Сборка и исходники

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

Проект снова на C++, SDL и Boost, плюс появилась маленькая вставка на ассемблере — для синтезатора.

Очень много шейдеров.

Как обычно ниже про интересные места в коде.

Cнова кастомный random-генератор:

/** 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:

Персональный компьютер БК 0011М (1980-е годы)

Так что дух хардкора еще очень даже жив.