making of "blash" - код и железо



(осторожно, большие фотографии и обилие говнокода под катом!)

Так как я обещал продолжение, то оно уже тут :) Предыдущие записи можно найти по тегу «blash».

… Итак, общая идея демы выработана, теперь нужно ее реализовать. С платформой я уже определился, теперь требуется выбрать язык, на котором и будет написан код. Выбор был, честно скажу, небогат:


  • от Бейсиков на PC меня уже тошнило — QuickBasic слишком медлителен (однако даже на нем делают демы :), а порт FreeBasic под DOS, мягко говоря, неидеален, более того, обладает целым рядом глюков.
  • Паскаль. Я делал некоторые наброски на Turbo Pascal 7.0, в частности, генерил таблички для ldi (Processing? какой Processing?), но в плане скорости голый Паскаль был далек от совершенства, заставляя писать огромное количество кода на inline-ассемблере, да еще и без толковой поддержки инструкций IA-32 (читай i386 и выше), да еще либо в реальном режиме с пресловутыми 640 килобайтами, либо с косячным DPMI-сервером… Ну уж неееееееееееет :). Добавим сюда и проблемы со звуковыми системами (плееров .XM-файлов под TP7 я в природе не видел, а без музыки дема — не дема)
    FreePascal тоже был отметен, но по другой причине — проблемы компиляции и отладки исполняемых файлов, да и размер не прельщал.
  • Ассемблер. Хардкор-вариант, на который я просто не был морально готов.

Оставался последний вариант — С. Watcom C.

Прежде всего, Watcom я полюбил за великолепную оптимизацию выходного кода (зачастую вставки на ассемблере по скорости проигрывали написанному на Си коду, что меня первое время серьезно удивляло), отличную поддержку защищенного режима и обилие внешних сторонних библиотек. Я нашел Open Watcom 1.9, настроил среду и начал писать.

DOS-расширитель — конечно же PMODE/W! Скорость, самостоятельность (не нужен отдельный EXE-шник, в отличие от DOS/4GW) и отсутствие лишних вопросов (это относится к DOS32) — главные его достоинства, да и памяти теперь можно использовать хоть все четыре гигабайта (которых у меня нет ;)

Ах да, я чуть описать платформы, на которых все писалось и тестировалось:
  • Pentium 200 MMX (время от времени разгоняемый до 250 МГц)\ ASUS TXP4 на i430TX \ 128 МБ SDRAM \ Matrox Millennium \ 40 ГБ IDE \ Realtek 8139C \ AWE64 Value \ Windows 98SE — основная кодингмашина (под нее все и писалось)
  • Pentium 133 \ LuckyStar P55CE на i430FX (казалось бы, причем тут nyuk … ;) \ 32 МБ EDO \ пачка S3-шек \ пачка всяких звуковух — на этой платформе фиксилась финальная версия
  • Celeron 300A \ некая помидорина на i440LX \ 32 МБ SDRAM \ GeForce 2 MX200 \ разные звуковухи — а эта машина была наиболее близкой к компотачке — там стояла P2-333
  • … ну и конечно же DOSBox различных версий и сборок

На основной машине в качестве редактора использовался Notepad++, а компьютеры соединялись локальной сетью, что позволяло быстро проверить свеженаписанный код на целевой машине.

Из внешних либ использовался Useless Module Player v1.11 beta by FreddyV\Useless. В принципе, если бы я писал дему сейчас, я бы заюзал Indoor Music System 0.6 by pascal, так как я устал ловить глюки в USMP (например, встроенная система таймеров вызывала дергания и секучки на экране, так что пришлось писать таймер самому), хотя… благодаря понятным исходникам USMP я даже добавил в нее поддержку Covox (для прикола :). Но при этом косяков в проигрывнии XM-ок (а именно в этом формате и написана музыка из демы) не было, особенно после установки багфикса.

Отладка на различных платформах — важная вещь, так как можно отловить различные непредвиденные глюки :)

Здесь лирическое(?) отступление заканчивается и начинается, собственно, разбор blash по косточкам. Поехали!

Начало

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

#include <math.h>
#include <strings.h>
#include <stdlib.h>
#include <conio.h>
#include <stdio.h>

#include "usmplay.h"
#include "rtctimer.h"


Далее идут константы, общие массивы и вспомогательных функции:

#define X_SIZE 320
#define Y_SIZE 200
#define DIST   300

typedef struct {
    float x, y, z, d;
} vertex;

typedef struct { float x, y; } vertex2d;

short sintab[65536];
float sintabf[65536], costabf[65536];

unsigned char  *screen = 0xA0000;

#define pi        3.141592653589793
#define ee        1.0E-6
#define bb        2 * 1.0E+4
#define bb2       1.0E+6

#define sat(a, l) ((a > l) ? l : a)
#define sqr(a)    ((a)*(a))
#define sgn(a)    (((a) > 0) ? 1 : -1)

USM *module;
int notimer = 0, noretrace = 0, mode13h = 0, manual = 1, lowres = 0, fakelowres = 0


По процедурам в #define стоит пройтись отдельно. sat(a, l) производит проверку на выход целого положительного числа a на выход из диапазона [0, l], в случае выхода значение ограничивается l. Именно эту продедуру я использую для насыщения палитры\картинки в некоторых частях (в том числе при наложении спрайтов на экран путем сложения, чтобы не переполнить значения)
sqr вычисляет квадрат числа, а sgn — его знак (понадобится потом)

Константы ee и bb — соответственно достаточно малое и достаточно большое число, используются для предотвращения ошибки деления на ноль в некоторых случаях.

Ниже — инициализация таблички синусов:

void initsintab() {
    int i, j;
    float r;
    
    for (i = 0; i < 65536; i++) {
        r = (sin(2 * pi * i / 65536));
        sintab[i] = 32767 * r;
        sintabf[i] = r;
        r = (cos(2 * pi * i / 65536));
        costabf[i] = r;
    }
}


Далее идут различные аппаратные хаки, в частности, связанные с выводом картинки. В этой части без описания регистров VGA-адаптера не обойтись — вот оно

Ах, да:
void setvidmode(char mode) { 
    _asm {
        mov ah, 0
        mov al, mode
        int 10h 
    } 
}


320x200 60Гц, или как ускорить дему без лишних хлопот
Вся демка работает в режиме 320x200 256 цветов (стандартный режим VGA 13h), но… с небольшим хаком:

void set60hz() {
    // again thanks to type one for info ;)
    ///*
    outp (0x3D4, 0x11); outp(0x3D5, (inp(0x3D5) & 0x7F)); // unlock registers
    outp (0x3C2, 0xE3);   // misc. output
    outpw(0x3D4, 0x0B06); // vertical total
    outpw(0x3D4, 0x3E07); // overflow
    outpw(0x3D4, 0xC310); // vertical start retrace
    outpw(0x3D4, 0x8C11); // vertical end retrace
    outpw(0x3D4, 0x8F12); // vertical display enable end
    outpw(0x3D4, 0x9015); // vertical blank start
    outpw(0x3D4, 0x0B16); // vertical blank end
    //*/
}


Данная процедура перепрограммирует регистры VGA-адаптера для снижения частоты развертки до 60 Гц, чтобы слегка ускорить дему на слабых машинах. Кроме того, данный режим еще и исправляет некорректное соотношение сторон в стандартном режиме 13h (пикселы вытянуты по вертикали).

Идея данного хака встретилась в текстовике от Type One \ Pulpe ^ TFL-TDV, в котором описана туева хуча различных Super- и не только VGA трюков (в частности, способы наступлений на грабли перевести карточку во всякие нестандартные режимы, вроде 320x200 16 страниц или использование BitBLT). Сейчас особой ценности сей файлик не представляет, но почитать стоит.

На реальной машине картинка выглядит вот так:


Вообще, этот режим должен быть совместим по развертке со стандартным режимом 640x480 60Гц и работать на любой видеокарте и мониторе, но на всякий случай его можно отключить ключом «70hz»

LowRes-режим
Этот режим был запилен в финальной версии для слабых машин (медленнее P133), чтобы избежать неприятных тормозов и даже зависаний. Суть его проста — некоторые эффекты при его активации рендерятся в режиме 160x200, растянутом до 320x200, что позволяет тратить меньше времени на отрисовку.

И вот тут-то и начинаются грабли. Вначале режим был сделан из вышеописанного текстовика таким образом:
// method one - set mode 0xD and turn 256 color mode on hand
    // 10% works on matrox, ati and S3 (serious palette corruption)
    // 1%  works on trident (even more serious corruption)
    // i guess that it should work on tseng, but dunno
    
    setvidmode(0xD);
    
    outp (0x3D4, 9); outp(0x3D5, ((inp(0x3D5) & 0x60) | 0x3));
    outpw(0x3D4, 0x2813);
    
    // unlock S3 extensions
    outpw(0x3C4, 0x0608);
    outpw(0x3D4, 0x4838);
    // and test for presence of S3 card
    outp (0x3D4, 0x30);
    // if S3 detected - use S3 method of VCLK/2
    if (inp(0x3D5) >  0x80) {
        outp(0x3C4, 1);    outp(0x3C5, (inp(0x3C5) & 0xF7));
        outp(0x3C4, 0x15); outp(0x3C5, (inp(0x3C5) | 0x10));
    }
    // lock S3 extensions
    outpw(0x3C4, 0x0008);
    outpw(0x3D4, 0x0038);
        
  
    outpw(0x3C4, 0x0E04);
    outpw(0x3D4, 0x4014);
    outpw(0x3D4, 0xA317);
    outp (0x3CE, 5); outp(0x3CF, (inp(0x3CF) | 0x40));
    inp  (0x3DA); outp(0x3C0, 0x30); outp(0x3C0, 0xC1);
    inp  (0x3DA); outp(0x3C0, 0x34); outp(0x3C0, 0x00);
    
    


Суть его ясна из комментария — включаем режим 0Dh (320x200 16 цветов) и вручную переключаем видеокарту в 256-цветный режим. Где-то тут затесался хак для видеокарт S3 — он использует вместо VGA-шного делителя пикселклока на два полудокументированный в даташитах S3-шный, и он даже работает (вполне возможно, что я впервые заставил работать режим 160x200 256 цветов на S3-шках :D, но не буду голословным)

Однако запуск на Matrox и S3 привел вот к такому результату:


Туннель превратился в месиво :)
На других карточках эффект был еще хуже. На NVidia монитор выдал «power saving mode» и отрубился, на ATi Rage 128 система просто зависла. На остальных картах режим просто не включился, выводя черный экран либо просто зависая.

Тогда я решил попробовать второй способ:

// method two - set mode 13h and then load horiz.params from mode Dh
    // 100% works on matrox, 70% on S3 (palette corruption)
    // does not work on nvidia and crashes on ati (why?)
    
    //setvidmode(0x13);
    outp (0x3D4, 0x11); outp(0x3D5, (inp(0x3D5) & 0x7F));
    
    outpw(0x3C4, 0x0901); // FUCK YOU S3! :)
    
    // but...they strikes back!
    // unlock S3 extensions
    outpw(0x3C4, 0x0608);
    outpw(0x3D4, 0x4838);
    // and test for presence of S3 card
    outp (0x3D4, 0x30);
    // if S3 detected - use S3 method of VCLK/2
    if (inp(0x3D5) >  0x80) {
        outp(0x3C4, 1);    outp(0x3C5, (inp(0x3C5) & 0xF7));
        outp(0x3C4, 0x15); outp(0x3C5, (inp(0x3C5) | 0x10));
    }
    // lock S3 extensions
    outpw(0x3C4, 0x0008);
    outpw(0x3D4, 0x0038);
    
    outpw(0x3D4, 0x2D00);
    outpw(0x3D4, 0x2701);
    outpw(0x3D4, 0x2802);
    outpw(0x3D4, 0x9003);
    outpw(0x3D4, 0x2B04);
    outpw(0x3D4, 0x8F05);
    
    outpw(0x3D4, 0x1413);


Результаты были уже лучше — на Матроксе и S3 картинка стала выглядеть правильно. Правда, остались кое-какие глюки с S3 (тормозит RAMDAC, из-за чего часть палитры терялась, но пофиксил). На остальных картах режим опять не заработал.

Тогда я решил сделать еще и его эмуляцию — пикселы просто дублировались по горизонтали. Для выбора режима сделал небольшую менюшку:


    if (lowres == 1) {
        puts("select 160x200 mode: ");
        puts("1 - hardware (Matrox\\S3\\Tseng?)");
        puts("2 - fake (other cards and S3 also if first one is buggy)");
    
        do {ch = getch();} while (!strchr ("12\x1B", ch));
        fakelowres = ((ch == 0x32) ? 1 : 0);
        if (ch == 27) {KillAll();}
    }


В общем, в lowres-режиме дема вполне смотрибельна и на Pentium 90 (не было возможности проверить на 486, но если вдруг заработает, пишите :)

Timeline, или просто «план»

В процессе работы над демой получился такой план:

  • вначале идет небольшая пауза до 32-й строки нулевого паттерна (для синхронизации)
  • первый туннель (паттерны с 0 по 4)

  • второй туннель (4 — 8)

  • первая 3D-фиговина (9 — 0xC)

  • четыре twirl'а подряд (0xD — 0x14)

  • гритсы с 3D-бубликом (0x15 — 0x1С)

  • free-directional туннель (0x1D — 0x25)

  • free-directional плоскости (0x16 — 0x2D)

  • конец! :)

Сами части просто инклудились отдельными исходниками в основной файл:
#include "parts\\tunnel.c"
#include "parts\\tunnel2.c"
#include "parts\\3dstuff.c"
#include "parts\\twirl.c"
#include "parts\\twirl2.c"
#include "parts\\twirl3.c"
#include "parts\\twirl4.c"
#include "parts\\3dstuff2.c"
#include "parts\\fdtunnel.c"
#include "parts\\fdplanes.c"


Каждая часть торчала наружу двумя процедурами — <название>_init() и <название>_main(). Первая процедура вызывалась во время инициализации, вторая уже во время работы демы.

В общем инициализация выглядела вот так:


    for (p = 1; p < argc; p++) {
        if (strcmp(strupr(argv[p]), "NOTIMER") == 0)   notimer   = 1;
        if (strcmp(strupr(argv[p]), "NORETRACE") == 0) noretrace = 1;
        if (strcmp(strupr(argv[p]), "70HZ") == 0)      mode13h   = 1;
        if (strcmp(strupr(argv[p]), "LOWRES") == 0)    lowres    = 1;
        if (strcmp(strupr(argv[p]), "SETUP") == 0)     manual    = 0;
    }
    HardwareInit(_psp);
    rtc_initTimer();
    if (manual == 0) {USS_Setup();} else {puts("run \"blash setup\" for manual sound setup"); USS_AutoSetup();}
    if (Error_Number!=0) { Display_Error(Error_Number); exit(0); }

    if (notimer   == 1) {puts("timer sync disabled\0");}
    if (noretrace == 1) {puts("vertical retrace sync disabled\0");}
    if (mode13h   == 1) {puts("320x200 70Hz mode used\0");}
    
    cputs("init .");

    module = XM_Load(LM_File, 0x020202020, "musik.xm");
    if (Error_Number!=0) { puts(".\0"); Display_Error(Error_Number); exit(0); }
    
    cputs(".");
    initsintab();
    cputs(".");
    t1_init();
    cputs(".");
    t2_init();
    cputs(".");
    fx1_init();
    cputs(".");
    w1_init();
    cputs(".");
    w2_init();
    cputs(".");
    w3_init();
    cputs(".");
    w4_init();
    cputs(".");
    fx2_init();
    cputs(".");
    fd1_init();
    cputs(".");
    fd2_init();
    puts(".");
        
    puts("get down! ;)\0");
    
    setvidmode(0x13);    

    if ((lowres == 1) && (fakelowres == 0)) {set160x200();}
    if (mode13h == 0) {set60hz();}
    
    USS_SetAmpli(150); // to prevent clipping on sbcovoxpcspeaker                 
    USMP_StartPlay(module);
    USMP_SetOrder(0);
    
    if (Error_Number!=0) { setvidmode(3); Display_Error(Error_Number); exit(0); }


… и основной цикл:

while (Row < 32) {}
    inp  (0x3DA); outp(0x3C0, 0x31); outp(0x3C0, 0xFF);
    t1_main();
    inp  (0x3DA); outp(0x3C0, 0x31); outp(0x3C0, 0);
    t2_main();
    fx1_main();
    if ((lowres == 1) && (fakelowres == 0)) {setvidmode(0x13); if (mode13h == 0) {set60hz();}}
    w1_main();
    w2_main();
    w3_main();
    w4_main();
    fx2_main();
    
    if ((lowres == 1) && (fakelowres == 0)) {set160x200();     if (mode13h == 0) {set60hz();}}
    fd1_main();
    fd2_main();
    
    normal = 1;
    KillAll();

    
    puts("blash - final - b-state - 2015\0");


Напоследок, нам нужно все за собой подчистить — для этого используется процедура KillAll():

void KillAll() {
    USMP_StopPlay();
    USMP_FreeModule(module);
    
    setvidmode(3); rtc_freeTimer();
    if (Error_Number!=0) { Display_Error(Error_Number); exit(0); }
    if (normal == 0) {puts("hey, why you pressed that escape key?!\0"); exit(0);}
}


А разбирать код частей мы начнем с twirl'ов и туннелей уже в следующей статье.

P.S. кстати, в финальной версии демы есть скрытая часть — готовьте отладчики и HEX-редакторы! (осторожно, не рекомендуется к просмотру господину lvd , извини :)

20 комментариев

avatar
Артём, я ведь правильно понимаю, всё это 2015 год, не 2000 а современность? Любо-дорого посмотреть на всё это. Я думал, что один такой вот остался, и пишу на всё какие-то конвертеры, компиляторы, кранчеры, линкеры, вожусь с ХМками. Я уже на столько привык к критике, -«что вон все на виндовсе10 сидят, а ты всё под старьё пишешь», в итоге просто перестал рассказывать кому либо про путь, по которому шёл, что бы получить конечный результат.
avatar
Писать под себя всякие тулзы приходится по одной простой причине — часто готовые проги не удовлетворяют запросам, да и возможностей для данной конкретной задачи не хватает. Например, в случае с ldi нельзя было просто посчитать все на месте (вообще-то можно, но… немного медленно :), поэтому пришлось писать различные генерилки текстур\табличек, батники для пакетной сборки, зато и самому интересно, и результат радует.

Да и blash писалась по принципу «делаем прод и по пути делаем побочный стафф, который потом обязательно пригодится» :)
avatar
аналогично можно сказать и про железо — одного только досбокса не хватило бы для ловли всех багов.
avatar
Ооо… Досбокс вообще не рассматривается как что-то для ловли багов. Вот тут собственно и проблема. Если писать под дос, то нужно выбирать между массой, которые будут смотреть результат на реале и теми, кто будет всё это пускать под эмулятором. Я бы сказал так, что если ориентироваться под эмулем, то это путь серьёзных ограничений. Из моей практики на пентиуме с частотой 466mHz, делается практически всё фреймово.
avatar
Очень впечатляет.
Супер!
avatar
Robus , спокойствие, только спокойствие! Не перевелись ещё психи на земле русской!
У меня больше половины времени — это именно такие дела, бесконечные конверторы, генераторы графики, генераторы кода, компрессоры самопальные, и т.д. и т.п.
avatar
Лёша, да, я знаю, что ты такой же. Твой подход я увидел сразу при первом знакомстве. Просто очень приятно встречать людей, которые готовы отдать кучу времени, что бы написать десяток конвертеров ради того, что бы результат был на пять с плюсом.
avatar
Но твой пример всё же поучителен! Писать свой ассемблер и свой трекер я очень надеюсь избежать!!!
avatar
Так нет альтернативы. Я же их написал не от того, что просто пришло в голову, а от того, что не мог Dreamer писать музыку на PT3, только ASM. Сколько не турбируй плеер, ничего не получится. Вот и пришлось сделать свой формат mason'а, который изначально был простым компилятором на ПиЦи, на входе были любые модули PTх или ASM, а на выходе уже мой формат. Это он уже потом перерос в редактор. потому, что появились запросы о специфической музыке и универсальности типа 2хАУ. Ну а про ассемблер я вообще молчу, тут без него у меня стопор начался ещё в 2000 году. Никогда не забуду этот «ад» со сборкой демок. Теперь один ассемблер всё собирает и выдаёт конечный пакованный файл.
avatar
Но вот если бы ты начал, как я, всерьёз пару лет назад и у тебя был бы sjasmplus — ты бы всё равно взялся писать свой ассемблер? Потому что я понимаю про сборку на реале, «как раньше», и, конечно, в этом смысле, совершенно с тобой согласен что это несерьёзно. Но сейчас есть альтернативы, в чём-то не такие мощные как у тебя сейчас, но всё же и не настолько неадекватные как раньше. Это всё же меняет приоритеты, понимаешь?
avatar
Бесспорно взялся бы писать свой асм. sjasmplus не даёт главной вещи, это симулятора внутри асма, на котором у меня построены все проекты. Для того что бы мне перевести под классический асм хотя бы несколько эффектов, я уже молчу про проекты, нужно написать вспомогательных тулзов около сотни. И в итоге исходный код превратится в мега-монстра. А на данный момент все эти тулзы в львиной своей доле написаны на этом же компиляторе, и для того что бы откомпилировать любой пакер, конвертер, кранчер, мне нужен только один компилятор. И в итоге у меня получается вот так:
Include «FONT\crunch.az8»
LD HL,TEXT
CALL PRINT
DI:HALT
TEXT DB "Hello Speccy",0

Что видишь ты? Для тебя это текст «Hello Speccy», но в реальности кодировка символов стала максимально приближенная к нарисованному шрифту, где автор шрифта не рисовал знака вопроса, и поэтому он был автоматически выкинут. Всё это оптимизировалось в ветке предкомпиляции «FONT\crunch.az8», где анализировалась графика из картинки BMP, которая там же превратилась в бинарные данные, на них создалась табличка(виртуальная для компилятора) неиспользуемых символов, оптимизировались повторения в графике русской буквы «Р» и латинской «P», всё это превратилось в максимально ужатый бинарный кусок который лёг в память. И после исполнения «crunch.az8» любая информация заключённая в кавычки кодируется по таблице. И LD A,«P» в итоге в аккумулятор запишет некий символ после перекодировки. Это я привёл тебе простой пример, самый элементарный. Я молчу о том, что ты можешь откомпилировать свой код и тут же его в эмуляторе подсчитать по тактам, или часть своего кода подсчитать. Или сделать высвечивание пакованных данных, например в OSCOSS есть лица которые высвечиваются. Все они состоят из каких-то простых залитых полигонов, которые у меня высвечиваются какой-то процедурой, которая на каждую часть высвечивания лица стратит некое количество тактов. И тут мне приходит идея, хочу к лицам сделать снизу зеркальное отображение, и продлить границу разделение на бордюре. Вот всё это пропускается через одну команду компилятора, которая при компиляции эффекта подсчитывает сколько тактов занимает высвечивание каждой части лица, делает мне таблицу с конкретными числами в тактах, под каждую картинку-лицо, и я только из фиксированного числа отнимаю сумму тактов из таблички и жду оставшееся время до места продолжения линии на экране и бордюре. Всё, это конец моего кодинга в данном эффекте, график меняет себе пикселы в картинке, музыкант меняет нотки, а у меня жёсткий эффект сделанный из набора простых команд моего асма. И я не знаю как это сделать на sjasmplus? Я честно, клянусь, много раз пытался использовать разные компиляторы. но как правило компиляторы почему-то заботятся о том, что бы LDAB превращалось в LD A,B, но мне это не надо, это не проблема исправить опечатку, а вот когда я не могу дать волю своей фантазии, это для меня очень критично. Так что, Лёша, да, мне пришлось бы заново писать «asam», без него у меня весь пар уходит на гудок. Для меня возможности моего асма это как в 90-ые года писать на TASM 4.0, и потом кропотливо считать-считать-считать-считать-считать-считать…
avatar
Интересно рассказываешь! Видимо, я просто пока ещё недостаточно насчитался :)

Вообще, вот такие клёвые детали показывают одну вещь. Я думаю, было бы очень полезно, не только мне, послушать про твою работу над OSCOSS, послушать о принципах сборки, о подходе к эффектам, о подходе к дизайну кода и дизайну вообще. Не факт что люди сделают так же (я всё ещё не хочу писать свой ассемблер!), но вот такие рассказы о способах решения проблем — они очень полезны. Просто мозги прочищаются, волей-неволей начинаешь думать по-другому.
avatar
Автосборка проекта — всегда интересная часть, было бы любопытно почитать подробнее.
avatar
А разве можно как-то по-другому написать демо?
Альтернатива только запилятор. Если не запилятор, то все вот эти бесконечные конверторы и генераторы данных.
avatar
Тут то же есть куча этапов. У меня очень жестокий подход к написанию проекта. Я ставлю в рамки только тогда, когда понимаю, что без определённого инструмента не обойтись, например мой Mason, от которого я беру незаменимые возможности. Но если нет ограничений, я стараюсь идти по пути максимального удобства для творчества. Например ты график, и рисуешь в фотошопе, мы договариваемся что результат твоей работы это PSD, а метод передачи графики в конечный результат это BMP. Далее только моя проблема как это попадёт в код. И вот тут начинается разветвление, например путь который я вообще не признаю, где на промежутке между тобой и мной запускается утилита, в которой нажимается какая-то кнопочка(предварительно нужно 20 бегунков накрутить), потом получается какой-то файл, который в итоге загружается мной и с ним что-то делается, как правило не удобный формат и не оптимальный результат. Мне же всегда нужен под каждый случай свой формат. Поэтому я практически никогда не пользуюсь стандартной утилитой, просто на выходе будет то, что мне не подойдёт. Например у меня палитра из 128 значений, где нужно каждый 0ой и 15ый цвет оставить свободным, так устроена графика на гранях куба в SYNCHRе. Где эта утилита которая мне такое сделает? Её просто нет. Поэтому путь только писать свою, и эту утилита будет брать твой файл BMP, и запускаться каждый раз при компиляции демки, где нет участия человека, только жёсткий автомат с идеальным результатом для данного эффекта.
1. График нарисовал в удобном редакторе, или поправил один секретный пиксель.
2. Музыкант написал музыку не задаваясь вопросом сколько это будет занимать.
3. Клацнул на ентер.
4. Смотришь уже конечный запакованный результат, готовый к отправке, с лоадером, пакером, шмакером, кодером и другими супер-пупер вещами.
Главное нет вот этого промежуточного вызова утилиты и настроек. Так, что утилиты то же бывают разные.
avatar
Прочитал и осознал с некоторым недоумением что я как раз в процессе подготовки написания некоего автономного нарезателя графики :)
Похоже так в итоге и напишу я своего «Масона»! (бьюсь лбом об стену)
avatar
wbc , молоток, всё делаешь правильно. Приятно полюбоваться :)
avatar
Кстати, поясни, пожалуйста, есть ли у тебя фикс и если есть — на каком уровне он реализован (в том что ты уже положил я его не вижу).
avatar
про фиксинг расскажу попозже, когда дойду до музыки
avatar
отдельные личности уже нашил hidden part, так что… торопитесь :)
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.