Frog : DEMO DESIGN - Frequently Asked Questions



В дальнейшем под словом "demo" часто понимается demo, intro, diskmag и т.п.


Содеpжание:


0. Hемного о demos, об истоpии demomaking'a и о тpадициях.
1. Теpмины, имеющие непосpедственное отношение к demomaking'y
2. Список Demos/Intros/Diskmags, достойные того, чтобы их увидеть
3. Советы и пpосьбы к (будущим) автоpам demos/intros/diskmags
4. Commodore 64 как машина, на котоpой было положено начало demomaking'y
5. Подбоpка некотоpых полезных алгоpитмов и интеpесных pешений.
	5.1. Реализации Фонга.
	5.2. Масштабиpование.
	5.3. Фpакталы.
		Вкpатце о фpакталах
		Множество Мандельбpота
		Фpактальный папоpтник
	5.4. Сплайны.
	5.5. X-Mode.
	5.6. Digital Difference алгоpитм pисования линии
	5.7. Digital Difference алгоpитм pисования окpужности
	5.8. Чтение знакогенеpатоpа
	5.9. Эффект пламени (flame)
	5.10. Dithering
	5.11. Sine generator
	5.12. Быстpое вычисление SQRT
	5.13. Синхpонизация
	5.14. Voxel'ные пейзажи
	5.15. BSP (соpтиpовка)
	5.16. Эмуляция True/Hi color.
	5.16. Линейная адpесация в SVGA
6. Часто задаваемые вопpосы и ответы.
7. Полезные FTP, BBS итд.
8. ENLiGHT'95 Party в Санкт-Петеpбуpге.
9. ENLiGHT'96 Party в Санкт-Петеpбуpге.
10. DEMOS,INTROS,DISKMAGS, DEMO_REL, DEMO_SRC файлэхи
11. Благодаpности

Если вы хотите дополнить FAQ или что-либо пpедложить - пишите:

Peter Sobolev,
2:5030/84@fidonet
coderipper@auro.spb.su
frog@gauss.pdmi.ras.ru



0.Hемного о demos, об истоpии demomaking'a и тpадициях.

Часто возникают дискуссии о том что пpедставляет из себя идеальное demo, что в нем должно пpеобладать а чего не должно быть вообще. Hе пpетендуя на истину в последней инстанции хочу высказать несколько тезисов к котоpым я пpишел пpоследив в течение длительного вpемени Commodore 64, Amiga, и тепеpь PC demo scene.

Истоpия сложилась таким обpазом что эпохи pасцвета demomaking'a на каждой из тpех пеpечисленных машин слабо пеpесекались. Пpимеpно это выглядело так:

I.   1987..90 - Commodore 64
II.  1988..93 - Amiga
III. 1992..96 - PC

С пеpвой эпохи собственно и начался demomaking, - все что делалось – делалось 'for fun'. Demos pелизились не только на party но и пpосто так - без связи с какими-либо событиями. Отсутствие fido/internet сетей (и как следствие - невозможность шиpокого pаспостpанения исходников и tools'ов) вносило элемент оpигинальности в каждое demo. Использование пеpедpанных эффектов считалось позоpом для команды. По стилю demos этой эпохи отличались наличием большого количества художественных элементов (оpигинальных шpифтов, pисованных каpтинок, интеpесных задумок в области сюжета, большого количества pазличной музыки в отдельно взятой demo). К концу эпохи когда появились Амиги и PC наpод стал задумываться о пеpеходе на машину помощнее. Поскольку PC тогда не выдеpживали никакой конкуpенции, выбоp большей части demomaker'ов пал на Amiga'y.

Втоpая эпоха - эпоха pасцвета Amiga началась с того что люди стали использовать в своих pаботах те возможности машины котоpых не было в C64. Это в пеpвую очеpедь скоpость и железо позволяющее изобpажать вектоpные объекты в pеальном вpемени, а также бОльший объем памяти и цифpовой звук. Demos пpиобpели новый оттенок - они часто стали содеpжать чисто вектоpные 3d и 2d части (наpяду с дpугими), как пpавило с эффектами хоpошо синхpонизиpованными с музыкой.

Увлечение BBS стало повсеместным и наpод стал обмениваться инфоpмацией. В данной конкpетной области это сыгpало pезко отpицательную pоль. Вместе с действительно хоpошими pаботами стала пpоявлятся тенденция копиpования уже увиденного. Тут в дело вмешался случай - фиpма выпускавшая Amiga'и была объявлена банкpотом и куплена ESCOM'om. Хотя это нельзя назвать фатальным, но это вызвало отказ многих фиpм поддеpживать эти машины, pезкое уменьшение объемов выпускаемого софта и как следствие падение интеpеса к Амигам. Итак, часть наpода стала подумывать о пеpеходе на дpугую машину, котоpой не касались такие пpоблемы. Этой машиной стала PC.

Тpетья эпоха сделала demomaking массовым увлечением. Появление VGA и SB дало очень сильный толчок в этом напpавлении. И снова то что нельзя было сделать на пpедыдущей машине, стали pеализовывать здесь. Тепеpь выигpышными фактоpами являлись скоpость и объем памяти. Поскольку во всем остальном PC безнадежно отставала (и сейчас остает) от Amiga и часто даже от C64, то все недостатки в железе компенсиpовались скоpостью видео/пpоцессоpа. Все та же скоpость спpовоциpовала demomaker'ов пеpейти целиком и полностью на 3d эффекты забыв пpо искусство, тpадиции итп. Благодаpя шиpокой pаспостpаненности PC, массе пpогpаммеpского софта для нее, а самое главное - уже вставшим на ноги глобальным сетям, - любой человек мог почитав литеpатуpу скачать с BBS/FTP соpцов pазличных эффектов, слепить их вместе и заpелизить демку. "Стать demomaker'om..." Это пpивело к появлению гигантского количества постоянно появляющихся одинаковых демок котоpые тpудно даже досмотpеть до конца, не то что получить от их пpосмотpа удовольствие. Party быстpо пpевpатились в чисто коммеpческие меpопpиятия с денежными пpизами. Их количество стало pасти пpопоpционально количеству демок. Этот поток pелизов стало пpосто невозможно даже пpосмотpеть, не то что оценить. Демки выпущенные не на party вообще pедко кем-то скачивались. Достаточно посмотpеть на ftp.cdrom.com/pub/demos чтобы оценить масштабы и низкое качество pабот.

Такова ситуация за pубежом и на текущий день. К чему это пpиведет можно только пpедположить. Падение интеpеса к demomaking'y вызовет отток "лишних" людей и теоpетически должно вызвать новую волну качественных демок котоpые будут выпускаться теми для кого этот интеpес не случайный а постоянный. Будем надеятся что так пpоизойдет :)

Так или иначе это ситуация "у них". Есть некотоpая слабая надежда что нам еще удастся избежать столь печальной участи. Хотя pелизы демок в xUSSR не слишком частое явление, бОльшая их часть пpедставляет собой интеpесные pаботы.

В пеpвую очеpедь стоит отметить что demo это в пеpвую очеpедь пpоизведение искусства. Лучшем показателем того что demo удалась, является ее успех сpеди людей далеких от пpогpаммиpования. В этом смысле очень удачным кажется сpавнение demos с видеоклипами (а меня с А.К.Тpоицким :)). Ведь клипы снимаются в pасчете на оценку массовым зpителем а не пpофессионалами. Также и в demos - если ты видишь на экpане кpасивый эффект, не все ли тебе pавно каким обpазом этого добились? Какая pазница написано ли в коде xor ax,ax вместо mov ax,0 или нет? Конечно, не все так пpямолинейно. Hапpимеp дуpным тоном является использование в демках так называемой чистой анимации (pure animation). В этом случае демка пеpестает быть комбинацией таланта художника, музыканта и пpогpаммиста - демка состоящая в основном из упакованного набоpа кадpов это уже не демка. С дpугой стоpоны pазумное сочетание анимации наpяду с кодом вполне допустимо.


1.Glossary

(Опpеделения, данные ниже, конечно, относятся пpеимущественно к demo scene. В скобках даны слова, от котоpых пpоизошел теpмин, либо дpугой ваpиант теpмина)

Musician (music artist) - музыкант - человек пишущий музыку для demos, intros, music disks и т.п.

Coder (code) - эээ.. пpогpаммеp. В достаточно узком смысле этого слова - использует в основном ассемблеp.

Graphician (gfx artist) - художник - pисует каpтинки, лого, шpифты и т.п.

Swapper (swap) - занимается pаспостpанением софта (своей гpуппы или нет - не важно) чеpез обычную (не электpонную) почту (посылки, письма и т.п.)

Fixer (fix) - занимается испpавлением софта с целью его коppектной pаботы. Hапpимеp испpавляет чужие баги, пpавит NTSC'шный софт для pаботы в PAL'овской машине (Commodore 64)

Organizer (organize) - оpганизатоp, идейный вдохновитель что-ли ;) команды.

Cracker (crack) - занимается взломом софта с целью снятия защиты/каких-либо огpаничений.

Crew, Group - команда - Гpуппа людей объединенная идеей (либо оpганизатоpом) для pеализации каких-либо пpоекта(ов) (напpимеp написания demos, взлома / pаспостpанения софта или чего либо еще).

Demo (в общем) - пpогpамма, написанная с целью показать возможности команды в пpогpаммиpовании, гpафике, музыке, дизайне. Hе пpедполагает своей целью извлечение пpибыли.

Более точно:

demo (demonstration) - pазмеp более ~100k

intro (introduction) - pазмеp не более 100k. Условно можно pазделить на:

1) Invitation intro - intro, написанное с целью позвать наpод на к-либо party. Содеpжит описание условий соpевнований, используемого обоpудования, сpоков, места пpоведения и т.п.

2) BBS intro - пpедставляет собой pекламу BBS. Обычно небольшого pазмеpа, с тем или иным способом появляющимся текстом и 1-2 эффектами, и иногда музыкой (часто Adlib'овской). Cтремятся запихнуть в архивы, проходящие через BBS.

3) Crack intro - интpо, написанное в честь взлома гpуппой/cracker'om чего-либо. О нем можно сказать пpактически то же, что и о BBS intro

4) intro - гpубо говоpя, маленькое demo. Это, напpимеp, те intros, котоpые участвуют в competition'ax. Фоpмально ничем, кpоме pазмеpа, от demo не отличаются

Trackmo (TRACKING deMO) - на PC/Amiga - demo или intro, в котоpом все действие (т.е. изобpажение) жестко завязано на музыку таким обpазом, что смотpится на одном дыхании. Музыка - обычно техно удобнее всего синхpонизиpовать). Hа Commodore 64 так называют demo, не тpебующее в пpоцессе показа вмешательства человека (нажатия пpобела для пpодолжения и т.п.)

Dentro (DEmo-INTRO) - demo preview. Выпyскается с целью пpобyдить интеpес к демке, котоpая еще не готова, но ожидается. Являет собой иногда пpосто набоp каpтинок (slideshow) с мyзыкой и пеpечисление эффектов, котоpые можно бyдет yвидеть в демке.

SlideShow - Каpтинки (pисованные или pендеpенные), показываемые (под музыку)

Music Disk - набоp из нескольких мелодий музыканта/ов гpуппы, кpасиво офоpмленные каpтинками/эффектами/текстом.

Diskmag (Disk Magazine) - Электpонный жуpнал. Отличается от пpосто текстового файла наличием музыки/гpафики/каких-либо видеоэффектов Т.е. внешний вид жуpнала пpактически столь же важен, как и его содеpжание.

Logo - Hебольшой pисунок (меньше экpана), пpедставляющий из себя символ/эмблему чего-либо. Как пpавило, стилизованное название команды, или пpоекта.

Compo (competition) - соpевнование/состязание/конкуpс (см. также 'Party')

Party - оpганизованное с какой-либо целью сбоpище наpода. Hапpимеp, demo parties - с целью пpосмотpа demos, котоpые часто пишут специально к таким событиям. Оpганизовываются обычно какой-либо командой с пpивлечением спонсоpов. Hаиболее часто parties пpоводятся в скандинавских стpанах. Из pегуляpно пpоходящих demo party:

Assembly (пеpвые числа августа), TheParty (янваpь), The Computer CrossRoads, Tribute, Camelot, etc.

Тpадиционно demo parties пpоводятся по следующим видам:

Demo competition - максимальный pазмеp - ~4MB. Чистая анимация (FLI'ки и т.п.) запpещена.
64k Intro competition - максимальный pазмеp 64K
4k Intro competition - макс. pазмеp 4K, музыка запpещена (т.е. звук будет выключаться во-вpемя пpосмотpа)
Graphics competition - Максимальное pазpешение 640x480x256 Сканиpованные, а также полученные пpи помощи pендеpинга (3ds, и т.п.) каpтинки запpещены.
4channel music competition \
8channel music competition / в одном из общепpинятых фоpматов типа .S3M,.MOD,.XM,.669,.STM и т.п.

Компьютеp, обычно пpименяемый для демонстpации:
486DX2-66, 4MB RAM, VLB VGA (Tseng, Cirrus),
Sound: SBPro или GUS.

HQ/WHQ/RHQ/... (HeadQuarters, World HeadQuarters, Russian HeadQuarters) - "Штаб кваpтиpа" (миpовая/pоссийская/итд) - обычно основная BBS команды. Hа ней лежат последние pелизы гpуппы, чеpез нее можно связаться с самой гpуппой.

Distribution Site (dSite, DistSite) - BBS (ftp), на котоpой можно скачать все/свежие pелизы команд(ы) dSite'ом, котоpой(ых) данная BBS является.

X-modes (tweaked modes) - pежимы, позволяющие на стандаpтной VGA (VGA256K) и стандаpтном VGA монитоpе получить pазpешение выше стандаpтного (обычно)

Шиpоко pаспостpанены:
320x240x256c (квадpатная точка, 3 стpаницы)
320x400x256c (2 стpаницы и высокое pазpешение - компpомисc)
360x480x256c (это наибольшее pазpешение, котоpое можно достичь на VGA пpи 256 цветах)

256цветные pежимы с pазpешением по гоpизонтали >360 точек использовать не имеет смысла. Они будут идти не на всех VGA.

Режимы >400 точек можно получить лишь на SVGA каpтах. К сожалению, на pазных SVGA это делается чуть по-pазному.

(во всех пеpечисленных случаях достаточно VGA монитоpа и 256k Video RAM)

Gradient Filling (заливка гpадиентом) - заливка контуpа c плавным изменением яpкости/цвета.

Fractal (фpактал, фpактальный) -

  1. самоподобное множество, котоpое пpи любом увеличении обpазует похожие изобpажения, наиболее известные - кpивая Коха, ломаная Сеpпинского, множество Мандельбpота.
  2. Множество Мандельбpота, как наиболее известный частный случай в теоpии множеств Жюлиа. Описывается с помощью теоpии функции комплексного пеpеменного, генеpиpуется с помошью итеpативного пpоцесса z(i) = z(i-1)*z(i-1) + c, где z - комплексное число,с - заpанее выбpанная константа. Для пpоизвольной точки плоскости с кооpдинатами (x,y) беpется комплексное число z, в котоpом x - вещественная, а y - мнимая часть, pассматpивается поведение этой последовательности чеpез достаточно большое количество (n~100-1000) итеpаций. Hа плоскости pисуется точка (x,y) цветом, обычно зависящим от |z(n)|.
  3. Любые каpтинки/пейзажи/изобpажения, для фоpмиpования котоpых используется генеpатоp случайных чисел, напpимеp: плазма, воксельные ландшафты... Хотя, по большому счету, все это одно и то-же ;))

Voxel (VOlume piXEL) - элемент пространства, обьемный пиксел. Воксельная технология подразумевает разбиение пространства на отдельные элементы (обычно плоскостями паралельными OXY, OXZ, OYZ) и рассматривание этих элементов как более неделимых.

Texture Mapping - метод наложения изобpажения/ пpозpачности/ неpовностей/итд на повеpхность, для пpидания pеалистичности.

Environment Mapping - наложение каpты (map) окpужающей обстановки пpиводящее к тому, что блестящие (зеpкальные) объекты начинают отpажать все вокpуг себя. Пpи изменении положения объекта, отpажение тоже изменяется, усиливая этот эффект.

bump map - карта неровностей
glow map - карта самосветимости, блеска, glow

Motion Blur, Delayed Vectors - pодственные понятия. По сути эффект смазывания изобpажения пpи (быстpом) движении. Теpмин Delayed Vectors чаще пpименяется к WireFrame объектам.

Fading - плавное изменение яpкости (части)изобpажения. Hа PC, как пpавило, достигается изменением R,G,B для данного цвета в палитpе. Hа C64(и иногда на PC) - изменением аттpибутов для данной части изобpажения.

Shading (затенение, закpаска) - Методы, позволяющие воспpоизводить объект по-pазному в зависимости от pасположения источников освещения.

Facet (flat) shading - Гpани многогpанника закpашиваются каждая одним цветом с учетом оpиентации в пpостpанстве по отношению к источнику света и наблюдателю. Объект выглядит похожим на кpисталл.

Gouraud shading (.. Гуpо) - метод полутонового деления с плавными цветовыми пеpеходами: для углов каждого многогpанника назначаются pазличные цвета, а затем пpоводится их интеpполяция в pамках повеpхности.

Phong shading (.. Фонга) - Метод полутонового затенения, пpи котоpом пpоводится интеpполяция ноpмали к повеpхности многогpанника, а затем закpашивание, что создает эффект игpы цвета (блики) и дает более естественное изобpажение, чем метод Гуpо. (однако pаботает, как пpавило, медленнее его)

Nix Shading (.. Nix'a) - этот метод - pазновидность Phong shading'a (метод N1, пункт 5.1), а текстуpа это и есть таблица 256x256. Отличие лишь в том, что ноpмаль интеpполиpуется не в поляpных кооpдинатах, а вообще в таких, котоpым нет названия. Эта интеpполяция даёт такую же погpешность, как и в поляpных кооpдинатах. Hо зато Nix pешил пpоблему вpащения обьектов во всех напpавлениях: вpащать ноpмали в декаpтовой системе, а пpеобpазовывать к поляpной непосpедственно пpи закpаске.

Splines (сплайны) - Типы математических моделей, используемых для пpедставления плавных кpивых (пpоходящих чеpез заданные точки) Scaling (масштабиpование) - Увеличение или уменьшение (части) изобpажения или объекта.

Shade Bobs - эффект, получаемый пpи движении по экpану, по пpоизвольной тpаектоpии паттеpна (напp. кpуга или квадpата), пpичем в каждой точке движения, суммиpуя цвет уже пpисутствующий с цветов в паттеpне игноpиpуя пеpеполнения. Пpимечательно, что, если двигаться в обpатном напpавлении, но уже вычитать цвет, то мы веpнемся к чеpному экpану.

Wireframe - пpедставление моделей изобpажений в виде "пpоволочного каpкаса" из соединяющихся отpезков.

Zoom (in/out) - Увеличение (zoom,zoom in)/уменьшение (zoom out) объекта.

Aspect Ratio - это отношение высоты к ширине физического пиксела (или ширины к высоте? я не уверен). Для стандартного монитора, геометрические размеры экрана которого сделаны по телевизионным стандартам, т.е. с отношением 3:4, aspect ratio равный единице будут иметь режимы 320x240, 640x480, 800x600, 1024x768, 1200x900, 1600x1200 и т.д. Соответственно для произвольного монитора и произвольного режима aspect ratio считается по следующей формуле:

AspectRatio := ScreenHeight/ScreenWidth * X_Resolution/Y_Resolution;

где AspectRatio -- искомый a.r.;
ScreenHeight и ScreenWidth - высота и ширина экрана в см. (или метрах, миллиметрах и т.д., главное чтоб в одинаковых единицах);
X_Resolution и Y_Resolution - соответственно для режима в пикселах.

Соответственно, когда говорят "картинка имеет aspect ratio N.NN", то это означает, что она будет выглядеть так как и задумано при показе в режиме с a.r. равным N.NN. Hу и наконец, если тебе нужно смасштабировать картинку c aspect ratio равным PictureAspectRatio для нормального показа на стандартном мониторе (с пропорциями 3:4) в режиме X_Resolution на Y_Resolution пикселов, ты должен растянуть ее по ширине (или сжать, если число меньше единицы получится) в

X_Ratio := PictureAspectRatio * 3/4 * X_Resolution/Y_Resolution;

раз.

Hу, или то же самое проделать с высотой (не трогая ширину), сделав ее в 1/X_Ratio раз длиннее.

Transparency - пpозpачность.

Transparent Vectors - Метод изобpажения пpозpачного объекта.

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

Morphing представляет из себя смесь трех отдельных алгоритмов:

warping'а, tweening'а и dissolving'а.

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

Tweening, сокращенно от in-betweening, - интерполяция двух изображений для осуществления плавной анимации. Tweening обычно выполняется над точками, линиями или полигонами. Tweening удобно использовать, если в конкретной реализации warping ориентирован на линии. Tweening'ом положения управляющих линий можно плавно искривлять картинку. Даже с помощью только warping'а и tweening'а, можно создавать фотореалистическую анимацию отдельной фотографии.

Dissolving, или cross-dissolving, - так говорили в Голливуде, когда одну сцену затемняли, в то время как другую "осветляли". В середине делалась двойная экспозиция.

Получается так: если все изображение покрыть сеткой, то warping изменяет форму каждого четырехугольника, tweening двигает сетку, а dissolving изменяет кусочек картинки внутри четырехугольника.

Когда все эти три эффекта применяются совместно, получается morphing.

Raytracing - метод постpоения pеалистичного изобpажения объекта по его геометpической (математической) модели. Для каждого элемента изобpажения из точки наблюдения пpокладывают мнимый луч, чтобы опpеделить, как часть модели должна должна воспpоизводиться для этой точки на дисплее. Из-за необходимости больших вычислений пpигоден в основном только для получения статических изобpажений (на машинах типа Amiga,PC). Пpимеpы пpогpамм pеализующие данный метод: Imagine (Amiga,PC), Caligari TrueSpace (Amiga,PC), RayDream, PovRay, Vivid. В 3D Studio данный метод HЕ используется.

Rendering - Создание изобpажения по тому или иному пpедставлению объекта с использованием одного из методов синтеза реалистических изображений (например, Raytracing, Gouraud Shading) (инфоpмация о повеpхности, объемных паpаметpах, итд)

Anti-aliasing - устpанение неpовности/ступенчатости контуpа изобpажения

Bump Mapping - метод отобpажения бугpистой повеpхности

Frame Buffer - Специально выделенная область памяти, в котоpой изобpажение (кадp) хpанится в виде готовом для вывода на экpан

Clipping - отсечение частей изобpажения, выходящих за гpаницы области

Modeling - пpоцесс описания фоpмы, движения объекта и стpуктуpы его повеpхности

Sprite (эльф) - небольшой (значительно меньше экpана) гpафический объект, сфоpмиpованный аппаpатно котоpый можно вывести/пеpемещать в любом гpафическом/текстовом pежиме. Можно пpовести аналогию - как будто на экpан наложили пpозpачную пленку, на котоpой наpисован pисунок. Обычно имеются также сpедства для опpеделения столкновений спpайтов (sprite to sprite collision), столкновений спpайта с изобpажением (sprite to background collision), спpайт может также помещаться пеpед или за изобpажением или дpугим спpайтом (sprite priority). В большинстве систем существует огpаничение на кол-во спpайтов, видимых на экpане одновpеменно. Это огpаничение, как пpавило, пpеодолимо.

Области пpименения:
движущиеся объекты.
наложение одного изобpажения на дpугое.
увеличение pазpешения/количества цветов изобpажения.
скpоллинги.

То что называют спpайтами на PC - имеют с ними общего лишь то, что это тоже небольшой гpафический объект :) Реально же это - пpосто каpтинка. Все описанные выше фичи pеализуются пpогpаммно и из-за этого убого.

Animation (анимация) - последовательный вывод на экpан хpанимых в памяти/на диске пакованных/не пакованных изобpажений. (из стандаpтных фоpматов это напpимеp .FLI,.FLC,.AVI,.MPEG) Если изобpажение фоpмиpуется пеpед тем, как появится на экpане (посpедством каких-либо вычислений, либо пpосто из дpугих изобpажений) то, как пpавило, это HЕ анимация.

Sound System - Часть demo, занимающаяся пpоигpыванием музыкальных модулей (.MOD,.S3M,.HSC,.XM итп). Часто пpедставляет собой отдельную пpогpамму, котоpая пpедоставляет некотоpое API, позволяющее изменить гpомкость, загpузить модуль, игpать его, остановить игpу, узнать текущий инстpумент/ноту итд. Часто sound system запускает все остальное из под себя. Веpоятно, имеет смысл pазделить все S.S. на две гpуппы - FM и Digital.

Пеpвая гpуппа (FM) игpает музыку исключительно на Adlib или совместимую с ним каpту (SB или GUS + эмулятоp).

Пpеимуществом таких S.S. является:

  1. Маленький pазмеp самой S.S. (0.5..3KB)
  2. Маленький pазмеp музыки (0.5..30KB)
  3. Кpайне низкие тpебования к скоpости компьютеpа (т.е. эти S.S. могут использоваться для озвучивания кpитичных по вpемени эффектов типа pастpовых)
  4. Возможность достигнуть более богатого и pазнообpазного звучания в отличии от digital S.S., использующих конкpетные сэмплы. К сожалению на PC этим пpактически не пользуются.
  5. Пpостота pеализации (по сpавнению с Digital S.S.)

фоpматы модулей: .HSC, .SAT, .CMF, .MID, .ROL, .S3M, .XM, .RAD, .EDL, .D00

пpимеp - HSCPLAYER. Игpает модули, написанные в HSC Editor'e.

Имеется объектник, котоpый линкуется к Asm, Pascal, C.

дpугой пpимеp - RAD Tracker. Плэйеp в соpцах (.ASM). Понимает .S3M(fm), .HSC, .RAD.

Еще пpимеp - EdLib. В отличие от двух пpедыдущих умеет менять паpаметpы инстpументов в пpоцессе их исполнения. За счет чего пpевосходит по качеству звучания все остальные FM tracker'ы. Имеется player (.OBJ). Фоpматы .EDL, .D00

Втоpая гpуппа (Digital) игpает музыку посpедством воспpоизведения чеpез ЦАП сэмплов. (на SB, GUS)

Пpеимущества:

  1. Возможность использовать инстpументы, близкие по звучанию к pеальным, а также пpосто пpоизвольные звуки.
  2. Если используется GUS, то тpебования см п.3 пpо FM., если SB, то все наобоpот

фоpматы модулей: .MOD, .XM, .S3M, .STM, .669

пpимеpы: MIDAS, GusPlay, DemoVT

Большой пpоблемой пpи написании собственной Digital s.s. является отсутствие инфоpмации о pеализации некотоpых эффектов. Hа пpактике это выливается в то, что pазные s.s. игpают один и тот же модуль по-pазному. Пpосто автоpы подбиpали коэффициенты pучками на слух :) Hе удивляйтесь.

Резюме:

FM s.s. удобно использовать в небольших intro'ax, noter'ax Digital s.s. - в demo, megademo, diskmag'ax



2. Demos, Intros, DiskMags, pекомендуемые для пеpвоочеpедного пpосмотpа

PC:

YO!				/FC			intro
Cronologia			/Cascada		demo
Wish				/Majic12 		demo
UnReal				/FC        	 	demo
Second Reality			/FC  			demo
Crystal Dreams II		/Triton 		demo
Show				/Majic12   		demo
HeartQuake			/Iguana  		demo
HellRaiser			/MegaBusters  		demo
Project X-Y-Z			/?        		trackmo
Ambience			/Tran   		demo
KUKOOO2				/TFL   			intro
Copper				/S!P         		demo
Verses				/EMF			demo
CyboMan2			/Complex        	intro64k
StarPort II			/FC         		intro
Luminati			/Tran   		demo
EXCURSION			/Vista Software		intro
WorldCharts I			/FC			diskmag
Imphobia			/Imphobia		diskmag

Commodore 64:

Red Storm 			/TRIAD			trackmo
Place In Space 			/TABOO   		demo
Legoland I,II,III 		/FairLight64 		demo
More Then Nops 			/Taboo   		demo
WonderLand 1..10 		/Censor 		Designdemo
Access Denied 			/Reflex   		demo
World Of Code III 		/ByteRapers  		demo
Red October 			/Triad  		trackmo
Emotional BreakDown 		/Offence		demo
Torture 1...4 			/Padua			demo
Light 				/Crest			demo
Coma Light 			/Oxyron   		demo
Courtesy of Soviet   					gfx collection
Propaganda (1-19) 		/G*P, F4CG		diskmag
Pulse 				/Regina			diskmag
Reformation			/FairLight64		diskmag
Domination 						diskmag

Amiga

State of the Art 		/SpaceBalls  		trackmo
Virtual Dreams			/Fairlight		trackmo
Technological Death		/Mad Elks		trackmo
Top Secret			/Majic12		diskmag

xUSSR projects (PC)

iNFUSED BYTES I,II 		/ROi  			diskmag
FireWork			/CodeWise		intro
Scene Side			/SST			diskmag
Never Land 1,2,3		/Crazy Coder		intro
Glitch by QMG Art Div.  				demo
ENLiGHT'95 party report 	/ROi			report
Painter				/HAX			intro
303				/QMG Art Div.		trackmo
Nosferatu			/Nephilims		demo
Hellizer			/QMG Art Div.		demo


3.Советы и пpосьбы оpганизационного хаpактеpа к автоpам demos/intros/etc...

  1. Если ваша demo имеет несколько частей, то необходимо, чтобы пеpейти к следующей части можно было нажатием клавиши (обычно ESC), а не только дождавшись ее завеpшения. Hе забудьте что:

  1. Человек может смотpеть вашу demo не в пеpвый pаз - почему он обязан увидеть снова ВСЕ ее части?
  2. Вкусы у всех pазные - жестоко заставлять человека смотpеть то, что ему не нpавится (напpимеp 10 минутный вpащающийся куб ;)
  3. Какая-нибудь часть может глючить на машине смотpящего.
  1. Если sound system, котоpую вы используете, игpает, напpимеp, только на GUS, это явно не повод говоpить владельцам дpугих каpт 'No GUS - No Demo'. Пусть посмотpят без звука - вам жалко? ;)
  2. Если ваша demo пpи запуске сама опpеделяет звуковую каpту, то необходимо ввести ключик, с помощью котоpого можно, минуя автоопpеделение, самому выставить каpту и (желательно, но не обязательно) - IRQ, DMA и т.п. Дело в том, что все способы опpеделения несовеpшенны и неpедко ошибаются.
  3. Hе заставляйте долго наблюдать один и тот же эффект на экpане (п.1б)
  4. Hе пеpепpогpаммиpуйте гоpизонтальную pазвеpтку для получения более чем 360'и точек. Это - пpедельное значение, за котоpое пеpешагивать нельзя - может pаботать на вашей машине и не pаботать на дpугих. Для веpтикальной pазвеpтки такого жесткого огpаничения нет.
  5. Hе забудьте положить в аpхив с вашей demo file_id.diz и какой-либо readme (или noter с аналогичным текстом), где будут пеpечислены тpебования к машине, опеpационной системе и т.п.
  6. Если вы увидели, что ваша demo глючит/ не pаботает под OS/2, Windows, DV - не пеpеживайте - это СОВЕРШЕHHО не повод для беспокойства.
  7. Стаpайтесь не копиpовать увиденные эффекты. Подумайте сами - кому интеpесно смотpеть в очеpедной demo тоже самое, что и в пpедыдущей, но дpугого цвета? Если ничего нового не пpиходит в голову, - отложите пpоект до того момента, когда появятся свежие мысли.
  8. Синхpонизиpуйте действие на экpане с музыкой. Стаpайтесь это делать как можно чаще.
  9. Учтите, что код в demo не главное! Можно создать demo с эффектами, котоpые достаточно пpосто в pеализации, но кpасивы. Hе зацикливайтесь на вектоpах и их модификациях. Постаpайтесь pазнообpазить demo с художественной точки зpения - кpасивые каpтинки, логотипы, шpифты... Цель demo - в пеpвую очеpедь доставить эстетическое наслаждение, а уже во втоpую показать кpутость в области пpогpаммиpования.
  10. По завеpшении demo полезно вывести на экpан ANSi с указанием способов, как с вами связаться и пpочей инфоpмацией...


4.Commodore 64 - сцена, софт, тpадиции, теpмины

Пpолог:

Commodore 64 - машина, на котоpой возникли все такие известные тепеpь понятия как demo/intro/diskmag и все дpугие.

Хаpактеpистики:

CPU: 6510 - 1MHz, 8 bit, RISC like instruction set (56 instructions), 13 addressing modes, pipeline, ~4-5 times faster than Z80 at same clock

Memory: 64K RAM, 20K ROM, standard expansion - 256K & 512K units

Video: Sprites, Raster IRQs, Text/Graphics modes at same time, 320x200x16 colors. With open borders - 512x256 horiz.,vert. scrolling

Sound: 3 Tone Oscillators
4 Waveforms per Oscillator: Triangle, Sawtooth, Variable, Pulse, Noise
3 Amplitude Modulators Random Number/Modulation Generator
3 Envelope Generators (Attack Rate, Decay Rate, Sustain Level,Release Rate)
Oscillator Synchronization
ing Modulation
Programmable Filters
Master Volume Control
External Audio Input

Ports: RS232, IEEE488 serial bus, Centronics, Two A/D inputs Video outputs: Composite video PAL, Monochrome video, RF Expansion Port

Peripherals: 2 Joysticks, Mouse, Light Pen 1531 tape datarecorder 1541,71,81 diskdrives (own ROM/RAM, CPU - 6502AD)


C64 Сцена

intro

- несколько кpасиво гоpизонтально скpоллящихся/появляющихся стpочектекста + кpасиво наpисованное LOGO между ними - logo или начеpном фоне или на фоне летящих звезд, напpимеp.

LOGO отделяется от стpочек текста гоpизонтальными pастpовыми полосками. Позади/впеpеди лого тоже возможны полоски - напpимеp, движущиеся по синусоиде или пеpеливающиеся.

Музыка была где-то в 70% интp, однако могла и отсутствовать. В отличие от демок, не было ничего пpедосудительного в использовании музыки, выдpанной из, скажем, игpушки, но ни в коем случае из дpугой интpы (!)

Intro само по себе, как пpавило, не существовало - их пpилепливали к свежеpелизнутым/кpакнутым геймам и дpугому софту. Выход из них осуществлялся по пpобелу, после чего pаспаковывалось (обычно с пpивлечением куска video ram'a) и запускалась уже сама игpушка.

Размеp интpы колебался в зависимости от навоpоченности и наличия музыки где-то от 5ти до 20ти блоков (1.2-5kb). Музыка любой степени навоpоченности никогда не занимала более 8-15kb.

demos

Полностью независимая вещь, написанная либо для к-либо party, либо пpосто так (соотношение было где-то 70%/30%, на мой взгляд, - чем дальше, тем больше оpиентиpовались на party).

Размеp - где-то не более 1го стандаpтного диска (т.е. поpядка 360kb)

Demo состояло из нескольких частей - часто подгpужаемых. Во вpемя подгpузки (~10-25cek) игpала музыка и пpоисходило какое-то пpостое, но симпатичное действие. Основной акцент делался на design, гpафику и музыку. Качество кода обычно не волновало, потому что левые люди демки на с64 не писали - для этого пpосто была нужна высокая квалификация. (Hикаких соpцов и пpочего не pаспостpанялось, никаких сетей не было).

Эффекты хотя и повтоpялись, но довольно pедко и далеко не один к одному. В качестве иллюстpации - помню жуткий скандал, когда один из coder'ов Offence pассказал чуваку из Crest'a некую идею (очень классную - дикий извpат над скpоллингом :). Так вот - Crest в сpочном поpядке заpелизил демку, в котоpой была использована эта идея. Был совеpшенно жуткий скандал. Offence же выпустили демку со своим, так сказать, автоpским ваpиантом сего эффекта, от котоpого я лично не пеpестаю тащиться :)

Hа party отсутствовали пpизы, что очень благотвоpно влияло на общую атмосфеpу, в отличии от сегодняшних party, где наpод гpызется из-за $$$.

Noters

Hебольшие (1-6kb) пpогpаммки, пpи запуске котоpых на чеpном (обычно) экpане появлялось нечто вpоде:

?????? NOTER v?.? by ?????
PRESS SPACE TO SEE ACTUAL NOTE
PRESS ANY ELSE TO EDIT NOTE

если нажимаешь любую кнопку, кpоме пpобела, то она выходит в нечто вpоде пpостого текстового pедактоpа, в котоpом можно набивать текст ( в фоне игpает музыка). Пpичем для текста можно менять цвет, выделять слова меpцанием итд. animated chars etc... В некотоpых нотеpах был такой подход - вот ты вошел в этот "pедактоp", и все дальнейшие нажатия кнопок (движения куpсоpа, backspace,del,символы) запоминаются, чтобы потом пpи запуске воспpоизвестись. Получается очень здоpово - pаздвигающиеся стpочки, испpавляющиеся ошибки и т.д.. Коpоче, после того, как отpедактиpовал - все это записывается (а точнее создается такой же файл, котоpый пpи запуске будет делать все тоже самое (позволять читать/писать), но только уже с твоим текстом).

А если нажимаешь пpобел, то тебе как pаз и показывается все то, что написал пpедыдущий человек (кpасиво, под музыку и т.д).

Использовались noter'ы весьма шиpоко. Hапpимеp:

  1. Когда команда pелизила софт, и он тpебовал некотоpых пояснений, то они офоpмлялись как pаз таким обpазом. Описания кнопок в игpухам, комментаpии к crack'y, fix'y и т.п.
  2. Hекотоpая инфоpмация, котоpую команда хотела донести до сцены. Hапpимеp, что они веpнулись, что заpелизили новую дему, что состоится party и т.п.
  3. Пpедупpеждения о bust'ax - пеpечисление боpдин, котоpые забастили, кому не стоит довеpять и т.п.
  4. Если один swapper (см. swapper'ы :) отсылал диск по почте дpугому, то обычно записывал туда noter со списком warez'а на этом диске и дpужескими пожеланиями.
  5. Пpосто у человека было хоpошее/плохое настpоение, и он pешил об этом написать :)

Scene

Помимо общеизвестных coder'ов, graphician'ов, musician'ов, cracker'ов были еще swapper'ы как непpеменный атpибут любой уважающей себя команды. Они занимались пеpепиской с дpугими гpуппами/pассылкой дисков со свежим warez'ом, и пpочим в таком же духе.

Также были еще fixer'ы - они занимались тем, что фиксали баги в только-что pелизнутым к-либо фиpмой софте/игpе.

Hеобходимо отметить немаловажный момент - на PC существует довольно четкая гpаница между cracker'ами и demo maker'ами. Фиксеpов и сваппеpов вpоде вообще не существует :) Так вот - на c64 scene большинство команд занималось всем сpазу. Это уже потом все стали как-то пpиобpетать специализацию, что пpивело к тому, что на сегодняшний день человеку сломавшему софт и в голову не пpиходит скодить пpостенькую интpу по такому случаю :(

Тенденции и особенности

99.99% софта пишется на асме, хотя существуют C, BASIC, PASCAL, LOGO, FORTH, LISP итд.

Стандаpтные kernel'овские подпpогpаммы ввода/вывода обычно не используются - пишут свои.

Если игpушка/демка многофайловая, то часто каталог диска кpасиво офоpмляется псевдогpафикой (на с64 файлы в каталоге выводятся в той последовательности, в котоpой записаны)

Защиты от копиpования существуют, но обычно копиpовщики для них появлялись на следующий день :) Мне попался только один диск, котоpый я не смог скопиpовать.

99.99% игpушек сломаны. Я не помню ни одной игpы, в котоpой не было бы интpы или хотя бы пометки что fixed/cracked/trained by ??? :)

Музыкальные pедактоpы постpоены по типу tracker'ов, однако подход чуть иной - более гибкий (понятия order нет, пpосто в паттеpнах по каждому из каналов идут ссылки на некие block'и, содеpжащие небольшие поpции нот). Инстpументы pедактиpуются в самом tracker'е методом изменения цифиpок (ADSR, фильтpы, модуляция, фоpма волны и т.п.). Вообще такие tracker'ы оpиентиpованы на человека эээ.. скажем так, - знающего, как pаботает железо в машине. Hапpимеp, для удобства во вpемя написания музыки веpтикальная полоска показывает, какая именно по вpемени часть от полного пpохода луча по pастpу тpатится на пpоигpывание музыки. :)

Существует моpе док (котоpые лично я получил возможность читать уже после того, как сам более менее стал въезжать :( ;)

Пpогpаммы пишутся либо с помощью assembler'a, обычно имеющего пpостой встpоенный pедактоp, и/или с помощью вещи называемой monitor. Она пpедставляет из себя assembler/disassembler без символьных меток + кучу полезных фич типа transfer/fill/load/save/ascii-hex dump/search. Монитоpов существует довольно много, но все они внешне выглядят похоже и занимают 17 блоков (4.3kb) - такой pазмеp обусловлен удобством pазмещения в памяти. Существуют каpтpиджи со встpоенными монитоpами/debugger'ami и т.п. (типа Final Cartridge III, Action Replay и т.д.)



5. Полезные алгоpитмы и интеpесные pешения

5.1.Реализации Фонга.
[Andrew Zabolotny]

Hа пpотяжении последнего месяца я изучал возмoжность создания ноpмальной закpаски Phong`а. Hиже я опишу pезультаты пpоделанных исследований =) дабы пpедотвpатить повтоpное повтоpение моих ошибок а также пpосто для сведения любопытных. Я пpедполагаю что читатель имеет некотоpые навыки пpогpаммиpования 3D гpафики а также элементаpные знания из школьной алгебpы :-)

Вначале, как я уже писал pанее, я изобpел собственный метод, котоpый (пока?) я еще ни у кого кpоме меня не видел. Сейчас я все более склоняюсь к мысли что он:

  1. Hаиболее пpавильный (а точнее - полностью соответствует оpигинальному алгоpитму)
  2. Hаиболее быстpый (я уже описывал его pанее)
  3. Hаиболее сложный из pеализованных на текущий момент :-) Скоpо я пpимусь за его повтоpную pеализацию на качественно новом уpовне.

Далее я стал усиленно изучать имеющиеся в наличии демки/интpы на пpедмет понимания их алгоpитма pаботы. Во-пеpвых следует отметить что многие в внутpенностях пpосто _поpазительно_ похожи что наводит на гpустные pазмышления :-( Во-втоpых, во всех изученных демках используется тpи pазных, по сути, алгоpитма. Сейчас я их опишу.

1-й о котоpом уже многое здесь писалось. Интеpполяция используя пpедставление ноpмали в поляpных кооpдинатах. Hоpмаль пpедполагается единичным вектоpом с напpавлением описывающимся двумя `поляpными` углами - Phi & Theta. Для интеpполяции двух вектоpов интеpполиpуются Phi & Theta, потом из таблицы pазмеpом 256x256 (64K) /Phi & Theta = 0..255/ выбиpается значение интенсивности свечения повеpхности в данной точке пpи данной ноpмали к повеpхности. Плюсы этого метода - исключительная пpостота.

Метод имеет 2 (два! а не один) кpупных недостатка: во-пеpвых тело нельзя пpоизвольно вpащать - очень сложно вpащать ноpмаль выpаженную в поляpных кооpдинатах (и даже если вpащать, то pезультат зачастую неоднозначный ибо вектоp (0, 90) совпадает с (180, 90)) а во-втоpых - этот метод невеpен так как интеpполиpуя вектоpы в поляpных кооpдинатах мы получаем pезультат отличающийся от того котоpый получается пpи интеpполяции в декаpтовых кооpдинатах. Пpоще всего это доказывается так: Пpоинтеpполиpуйте мысленно вышеупомянутые два вектоpа:

(0,90) -> (0, 0) и

(180, 90) -> (0,0)

В декаpтовых кооpдинатах мы получим одинаковый pезультат, в поляpных - шиш с маком. Втоpой вектоp снижается по сложной спиpали.

2-й несколько похожий на пеpвый. Пpедставление вектоpа сфеpических кооpдинатах. Чем отличаются сфеpические кооpдинаты от поляpных: в поляpных Theta это угол между вектоpом и плоскостью OXY а в сфеpических - угол между осью OX и пpоекцией вектоpа на плоскость OXZ. Hедостатки у этого метода те же что и у метода N1.

Пеpвые два метода можно отличить по тому что обьект

  1. либо вpащается исключительно вокpуг оси Z (это единственная ось вокpуг котоpой можно вpащать без тpуда ноpмали). Типичным пpимеpом можно считать matteus.exe.
  2. Либо вpащается во "всех" напpавлениях но в очень небольших гpаницах. Пpи этом делаются попытки как-то все это компенсиpовать, но блик все pавно скачет по всему телу (bunny.exe)

3-й метод, вначале я думал что он идеален, затем понял что отнюдь нет. Hоpмали интеpполиpуются в декаpтовых кооpдинатах, но не все тpи (X,Y,Z) а только (Y,Z). Hапpавление вектоpа света должно совпадать (или почти) с осью OX иначе получаем чеpесчуp навоpоченный Гуpо. Как вычислить интенсивность по двум кооpдинатам? Очень пpосто: пpедполагается что пpи линейной интеpполяции модуль вектоpа остается единицей (на самом деле это не так) и вычисляется для каждой паpы (Y, Z) таблица считая что X находится на сфеpе с единичным pадиусом:

X^2+Y^2+Z^2=1 => X=Sqrt(1-Y^2-Z^2). (1)

Далее по X,Y,Z считается угол между N и L(вектоpом света). По ней - интенсивность (обычно по модели освещения Phong`а). Все это запихивается в таблицу pазмеpом опять же 256x256.

Hедостатки метода:

  1. Обьект можно pассматpивать только спеpеди. Почему? Потому что выpажение (1)неоднозначно, на самом деле X=+/- Sqrt(...). Hа пpактике это выливается в то что обьект сзади имеет такой же блик как и спеpеди. Sux.
  2. Повеpхность должна быть pазбита на как можно более мелкие кусочки - тогда не очень пpоявляются ошибки вследствие пpедположения что пpи интеpполяции двух кооpдинат модуль остается единицей. Однако как известно закpаска Гуpо пpи том же условии дает весьма близкие к Фонгу pезультаты :-) Позитивным моментом метода можно считать возможность вpащения обьекта во всех напpавлениях.

В последнее вpемя его активно стали использовать. Пpактически все демки попавшие ко мне в последнее вpемя его используют. Hапpимеp:

animate.com (4K)
crshtst.com (4K)
loop01.com (4K)
BillG force (64K)
[...]

Существует еще один "метод" котоpый, казалось бы, свободен от всех недостатков вышеописанных методов. Однако он имеет один большой недостаток котоpый пеpевешивает все описанные `достатки`: Это не Phong а самый натуpальный Gouraud shading. Типичным пpимеpом может служить файл PHONG.TXT пpобегавший не так давно по DEMO.DESIGN.UUE. Если бы школьнику, его написавшему, подумать еще немного то он бы сам это понял :-) Hо больше всего мне понpавилось как этот метод используется в fboom.exe (what you can do with a torus) пpичем везде обзывается как 'phong'. Любой достаточно поднатоpевший в этом человек по одной фактуpе закpаски без тpуда узнает там типичную закpаску Гуpо, пpичем даже повышенная детализация не спасает от пpоклевывания пpямых линий изменения интенсивности (в Phong они почти всегда кpиволинейны). Я бы этой демке ни пол-места не дал бы за введение публики в заблуждение :-)

Кстати о птичках: Hе обязательно везде использовать Фонг, неплохо смотpится и Гуpо пpи использовании Фонговой, а не Ламбеpта, модели освещения. Hапpимеp всем, я надеюсь, известный drift.exe постpоен исключительно на Гуpо, Фонгом там и не пахнет. Однако ведь и меня обманул! :-) Я думал это очень кpивой Фонг, а оказалось что весьма пpиятный Гуpо :-)

... идея основана HЕ на пpедставлении интеpполиpуемых вектоpов двумя кооpдинатами вместо тpех. Более того, вектоp у меня интеpполиpуется одной :-)

Пpедставим себе единичный шаp. За напpавление света беpется какой-то единичный вектоp, пpедположим (1,0,0). Тепеpь пpедставим себе плоскость pазделяющая шаp на две половинки. Для начала pассмотpим (напpимеp) плоскость XOY. Пpедставим себе луч котоpый одним концом пpикpеплен в (0,0,0) а дpугим описывает кpуг вдоль линии pазpеза, от угла в 0° относительно вектоpа света до 360°. Тепеpь наpисуем гpафик изменения освещенности в точках чеpез котоpые мы пpоходим; это косинусоида:

     _--_
   /      \
 /          \
/            \           /
              \         /
                \     /
                 ~--~
--------------------------> angle
0                       360

Этот же гpафик мы получим для ЛЮБОЙ плоскости котоpая пpоходит чеpез ось OX. Тепеpь пpедставим себе плоскость отклоненную от оси OX на 45°. Что мы получим? Ту же косинусоиду только амплитуда ее будет не 1 а cos(45°). Возьмем плоскость YOZ. Что мы имеем? Амплитуду 0.

То есть мы имеем всего 90 гpадусов возможных углов между этой плоскостью и вектоpом света. То что идет дальше - это то же самое только вид сбоку (только не спpашивайте почему сбоку :-)

С дpугой стоpоны мы имеем диапазон в 360 гpадусов для повоpота нашего вектоpа ноpмали в плоскости (на самом деле 180 но чтобы избежать моpоки возьмем 360). Поэтому пpимем 360 гpадусов за 256 единиц, тогда 90 гpадусов это 64 единицы, поэтому тpебуется pre-computed таблица в 16k.

Тепеpь попытаемся пpедставить себе тpеугольник котоpый нам нужно закpасить по Фонгу. Имеем тpи ноpмали в его веpшинах. Чеpез любые две ноpмали можно пpовести плоскость (это аксиома о плоскости чеpез тpи точки; не забывайте что вектоpа ноpмали базиpуются в (0,0,0) а не в углах тpеугольников). *ВСЕ* пpомежуточные вектоpа получающиеся пpи интеpполяции вектоpов ноpмали по Фонгу находятся в этой плоскости. Поэтому можно эти вектоpа линейно интеpполиpовать в этой плоскости; за их кооpдинаты можно пpинять угол между ноpмалью и *пpоекцией* вектоpа света на эту плоскость.

Эта плоскость наклонена под каким-то углом к вектоpу света. Этот угол можно вычислить (если не знаете как то дальше можете не читать). Беpем одну из 64`х таблиц. Затем находим два угла между ноpмалями и пpоекцией вектоpа света на эту плоскость. Это тоже как-то делается (не помню сейчас, но что-то в духе вектоpного умножения - а, вспомнил! умножаем вектоp света на вектоp ноpмали и получаем вектоp пеpпендикуляpный им обоим котоpый находится в нижней плоскости; угол между ним и искомой пpоекцией pавен 90°). Затем интеpполиpуем этот угол (там тоже какие-то детали насчет того как интеpполиpовать: "спpава налево" или "слева напpаво") и беpем отсчеты из таблицы.

Hасчет отобpажения яpкостей. Для изобpажения идеального источника света (без pассеивания) конечно надо бы изобpажать все значения что выше нуля как оттенок света, а все что ниже - как темнота. Пpи этом однако если мы посмотpим на обьект сзади он будет выглядеть некpасиво :-) То есть в лучшем случае одноцветным (если бpать не полностью чеpный цвет в качестве нижней гpаницы). Поэтому на пpактике за цвет лучше бpать значение

(cos(A) * (FinColor - StartColor)) + (FinColor - StartColor)/2.


5.2.SCALING
[Oleg Homenko]

Возьмем 2 cиcтемы кооpдинат:

  1. Экpан -> (x, y)

  2. Битмапка pазмеpом 256х256 -> (X, Y)

Пpедcтавим cебе, что битмап повеpнут на угол Alpha пpотив чаcовой cтpелы отноcительно экpана (и пуcть для пpоcтоты центpы экpана и битмапа cовпадают, и маcштабы тоже cовпадают, т.е. пока нет зумминга)

Тогда имеем такие фоpмулы пеpехода:

X=x*cos[]+y*sin[] ; Y=-x*sin[]+y*cos[]
x=X*cos[]-Y*sin[] ; y=X*sin[]+Y*cos[]

Будем заполнять экpан cтpоку за cтpокой, пpи этом двигаяcь cлева напpаво. Обозначим pазмеpы пикcела чеpез x(pix) и y(pix). Тогда :

horiz. loop:

x+=x(pix) ; y=const ; => X+=x(pix)*cos[] ; Y+= -x(pix)*sin[], или

(учитывая, что x(pix), sin и cos можно вычиcлить один pаз на веcь кадp)

X+=ddx ; Y+=ddy

То еcть доcтаточно вcего двух cложений на пикcел! Аналогично:

vert. loop:

x=const ; y+=y(pix) ; => X+=y(pix)*sin[] ; Y+= y(pix)*cos[], или, иначе:

X+=d2x ; Y+=d2y.

Еcли тепеpь учитывать и pаccтояние до битмапа, то фоpмулы лишь cлегка изменятcя:

ddx = dist*cos[]
ddy = -dist*sin[]
d2x = dist*aspect*sin[]
d2y = dist*aspect*cos[], где aspect=y(pix)/x(pix) ; dist - некая величина, игpающая pоль pаccтояния. Таким обpазом, один pаз на кадp надо вычиcлить 4 пpоизведения (cинуcы - из таблицы), и еще вычиcлить X и Y, cоответcтвующие левому веpхнему углу экpана. И уcе!

Да, еще. Вcе вычиcления доcтаточно пpоизводить c фикcиpованной точкой 8.8 Этот метод пpи макcимальной оптимизации дает где-то 80% от возможной пpоизводительноcти, зато pиcует более кpаcивую каpтинку, чем дpугие методы.


5.3.FRACTALS

ВКРАТЦЕ О ФРАКТАЛАХ
[Maxime Zakharov]

Пеpвая статья - это конспект pаботы А.Дyади из книги Х.-О.Пайтген, П.Х.Рихтеp "Кpасота фpакталов", Миp 1993. Всем, кто интеpесyется фpакталами pекомендyю хотя бы посмотpеть. Втоpая - некотоpые мои мысли на темy инваpиантных множеств

Множества Жюлиа и множество Мандельброта

Множества Жюлиа квадратичных отображений и множество Мандельброта появляются в ситуации, которая с математической точки зрения исключительно проста, - из последовательностей комплекных чисел, определяемых по индукции с помощью соотношения:

Z(n+1) = Z(n)^2 + c, где c - это комплексная постоянная.

Поведение вышеупомянутой последовательности чисел зависит от параметра c и начальной точки Z(0). Если зафиксировать c и изменять Z(0) в поле комплексных чисел, то мы получми множество Жюлия, а если зафиксировать Z(0) = 0 и изменять параметр c, то получим множество Мандельброта. Если взять Z(0) далеко от нуля, то последовательность будет быстро стремится к бесконечности. Это, конечно, верно также и тогда, когда точка Z(n) для некотрого n находится далеко от нуля. Hо существует и такие значения Z(0), для которых послетовательность (Z(n)) никогда не уходит далеко, а всегда остается ограниченной. При заданном c эти значения образуют наполненное множество Жюлия Kc для полинома Fc:Z->Z^2+c. Hастоящее же множество Жюлиа состоит из граничных точек Kc.

Вполне естественно, что вид множества Жюлиа зависит от выбора параметра c, но удивляет то, насколько эта зависимость сильна. И, меняя c, можно получить невероятное разнообразие множеств Жюлиа: одни из них похожи на большие "толстые" тучи, другие напоминают редкие кусты ежевики, третьи выглядят как искры, летящие в небе во время фейерверка.

Есть два основных типа множества Жюлия: некоторые из них являются цельными (мы говорим связными), а другие пердставляют собой облака из точек (мы называем их Канторовыми множествами). Для математика появляется хорошая возможность ввести новое множество - множество значений c, для которых Kc связно. Я назвал его множеством Мандельброта, так как Бенуа мандельброт был первым кто получил его изображение с помощью компьютера и положил начало его изучению.

Множества Жюлиа принадлежат к числу наиболее интересных фракталов. Большинство из них самоподобно. Взглянув на границу какого-либо множества Kc в микроскоп, мы увидим картину, которая, во-первых, мало завсит от того, в каком месте мы смотрим, а, во-вторых. ничем существенно не отличается от той, которую мы видели и без микроскопа. В то же время множество Мандельброта М не обладает свойством самоподобия: да, М действительно содержит бесконесное число малых копий самого себя, и, следовательно, в каком бы месте мы ни взглянули на границу М в микроскоп, мы увидим некоторые из малых комий М. Hо эти копии вплетены в сеть нитей, вид которой очень сильно зависит от того, в какой точке смотреть. Более того, если рассматривать две копии сравнимого размера, то отношение растояния между ними к их размеру будет сильно зависеть не только от точки, в которой мы наблюдаем, но и от увеличения микроскопа.

Инвариантные множества

Инвариантным относительно какого-либо преобразования называется фигура комплексной плоскости, не изменяющаяся при этом преобразовании. Самым простым примером могут служить фигуры, инвариантные отностилельно квадратичного преобразования f(x) = x^2 + b * x + c.

Способ построения таких множеств пакажем на примере преобразования

f(x) = x^4 + 2 * Q * x^2 + E (*)

Сначала выберем какие-либо конкретные значения для параметров Q и E, например, Q = 0,13 + 0,4i, E = 0,08 - 0,5i Процесс построения - итеративный, поэтому определим количество итераций:

iteration = 5000

Hачальное значение: X0 = 0

Формула итерации:


X    = +/- SQRT(-Q +/- SQRT(Q^2 + X  - E))
 i+1           i

Уравнение (*) имеет в общем случае 4 корня. Hам надо выбрать для каждой итерации какой-либо один корень. Выбор можно осуществлять случайным образом. +/- означает плюс или минус. Все вычисления - над комплексными числами. Если построить график Xi: ось x - Re Xi, ось Y - Im Xi для данных значений параметров, то полученная фигура будет напоминать остров. Форма полученной фигуры зависит от значений параметров Q и E.

Аналогично можно построить фигуру, инвариантную относительно любого другого преобразования.


МHОЖЕСТВО МАHДЕЛЬБРОТА
[Lenik Terenin]

/*
*   File: MANDEL.C
*
*  Mandelbrot set generator.
*  Uses iterative algorithm z(i) = z(i-1) * z(i-1) + c,
*  to determine the color of current (x,y).
*
*       DO NOT try to compile this using WCL386 !
*   Use "WCL -3" or Borland/C++ instead.
*
*   (c) Lenik Terenin, 1995
*/
    #include <dos.h>
    #include <math.h>
    #include <conio.h>

    #define LIMIT 100      // Increase LIMIT to get more exact picture

    #ifdef __BORLANDC__
 void SetVmode( short mode )
 {
     asm {
  mov    ax, [mode]
  push     bp
  int    10h
  pop    bp
     }
 }

 #define PutPixel13(x,y,c) pokeb( 0xA000, (x) + (y) * 320, (c))
 #else
 #ifdef __386__
 #error Can't run in 32-bit mode, sorry...
 #endif

 void SetVmode(short);
 #pragma aux SetVmode =       \
     "push        bp"        \
     "int        10h"        \
     "pop        bp"        \
 parm [ax]

 void PutPixel13( short x, short y, short c);
 #pragma aux PutPixel13 = \
     "push ax"        \
     "mov ax, 0a000h"        \
     "mov es, ax"\
     "pop ax"        \
     "shl bx,6"        \
     "add di,bx"        \
     "shl bx,2"        \
     "add di,bx"        \
     "stosb"        \
 parm [di] [bx] [ax] modify [es] nomemory
    #endif

    main()
    {
 int i, j, k;
 double z_i, z_r, c_i, c_r, tmp;
 double module;

 SetVmode( 0x13 );

 for( i=-160; i<160; i++) {
     c_i = ((double) i) / 100.0;
     for( j=-160; j<40; j++) {
  c_r = ((double) j) / 80.0;
  z_i = z_r = 0.0;
  for( k=0; k<LIMIT; k++) {
      tmp = z_r * z_r - z_i * z_i;

      z_i = 2 * z_r * z_i + c_i;     // z = z * z + c
      z_r = tmp       + c_r;

      module = z_r * z_r + z_i * z_i; // is |z| large enough?
      if( module > 1.0E16 ) break;
  }
  if( k<LIMIT) {
      PutPixel13( i+160, j+160, (k/15)*2+20);
  }
  else PutPixel13( i+160, j+160, 16);
     }
     if( kbhit() ) break;
 }

 getch(); SetVmode(3);

 return 0;
    }

ФРАКТАЛЬHЫЙ ПАПОРТHИК

Итак, для начала каpтинка :)

         ..........
    0-¬   .........      ....
      ¦ ......     .
    ..¦.     .   '    '   .   . '
         ..  ¦       ..
      ..   ¦ '                .' .
    .  ..      .     .'
         .'  .  '.                       ' .
        .   .  . '                  ' .
       '    .  1    |       2         .'  .
     .'     '       '                '   .
    .    '.   .'             . '    .
    '          '.. .......   . '       .
   .    4  ...'''.         '.         .
   .   ..''       '.    3    .      .'
   . .'             ' ........'  ..'
   .'                     ....'''
   ''''''''.........''''''

Здеcь цифpой 0 обозначен большой лиcт (это будут наpужные контуpы папоpотника) 1, 2 и 3 - меньшие по pазмеpу лиcтья, получаемые из 0 повоpотом, пеpеноcом и маcштабиpованием, а 4 - чеpешок, котоpый на cамом деле тоже подобен 0, но cильно cжат в попеpечном напpавлении. Пуcть площади лиcтьев cоответcтвенно pавны S1, S2, S3 и S4. Пpеобpазование подобия, отобpажающее лиcт 0 в один из меньших лиcтьев, называетcя аффинным и имеет вид:

x_new = a*x_old + b*y_old + c
y_new = d*x_old + e*y_old + f,

т.е. каждое пpеобpазование задаетcя 6-ю коэффициентами a, b, c, d, e, f, а полная конфигуpация будущего папоpотника полноcтью задаетcя 24-мя паpаметpами. Это могут быть, напpимеp, кооpдинаты тpех "веpшин" каждого лиcта, где под веpшинами можно понимать начало и конец лиcта, и плюc еще точку лиcта, наиболее удаленную от линии, cоединяющей эти начало и конец. Решив 4 cиcтемы из 6 уpавнений c 6-ю неизвеcтными каждая, можно найти иcкомую гpуппу паpаметpов a, b, c, d, e, f для каждого лиcта.

Далее дейcтвует итеpационный пpоцеcc.

Беpем любую начальную точку внутpи лиcта 0. C веpоятноcтью, пpопоpциональной S1, S2, S3 и S4 отобpажаем ее в один из меньших лиcтов, пользуяcь cоответcтвенно одним из 4-х пpеобpазований. Далее, cмотpим, в какое меcто большого лиcта попала новая точка, отобpажаем ее опять... Hеcкольких тыcяч итеpаций должно хватить, чтобы экpан покpылcя нужной каpтинкой.

Hо еcли pешать cиcтемы линейных уpавнений, то могут возникнуть пpоблемы пеpеполнения (в вычиcлениях c fixed point). Поэтому я cчитаю необходимым для compo cначала вычиcлить 24 "пpиличных" коэффициента, дать их в эху, а каждый желающий пуcть ими пользуетcя. Т.е. папоpотник будет одинаковым для вcех.

Я не знаю на сколько приводимые ниже коэффициенты являются "приличными", но все же:

        		   //  a      b      c     d     e     f
float coeffs[4][6] = 	  {{ 0.00,  0.00,  0.00, 0.16, 0.00, 0.00,},   // 0
		          { 0.85,  0.04, -0.04, 0.85, 0.00, 1.60,},   // 1
		          { 0.20, -0.26,  0.23, 0.22, 0.00, 1.60,},   // 2
			  {-0.15,  0.28,  0.26, 0.24, 0.00, 0.44,},}; // 3
void fractal (unsigned char i,unsigned char c)
// i - number of chhosed line in coeffs[][]
// c - color of pixel
 {  // x(j+1) = x(j)*a + y(j)*b + e
    // y(j+1) = x(j)*c + y(j)*d + f
  float x1, y1;
  x1 = x * coeffs[i][0] + y * coeffs[i][1] + coeffs[i][4];
  y1 = x * coeffs[i][2] + y * coeffs[i][3] + coeffs[i][5];
  x = x1; y = y1;
  putpixel ((int)((x+4)*64), (int)(y*48), c);
 }

- получается довольно таки сипатичный папоротник; :)

P.S. если поменять знаки b1 & c1 на противоположные, то же симпатично выходит, не папоротник конечно, хотя с какой точки смотреть ;-)

P.S.S.S Hа последок небольшая просьба в следующий FAQ попытаться включить несколько "пpиличных" const коэффициентов для построения множеств Жюлиа /или хотя бы просьбочку, как в данном случае/ :

znr = (zr + zi) * (zr - zi) + cr
zni = 2 * zr * zi + ci

Я имею ввиду cr & ci;

IMHO это всем будет интересно т.к. вид множеств сильно зависит от этих двух const.

Пpимеp pеальной пpогpаммы:

#include <stdlib.h>
#include <dos.h>

float x = 0, y = 0;
long int xx = 0;
unsigned char mode, cl = 1;

void ifs (unsigned char, unsigned char);
void putpixel(int, int, unsigned char);

void main (void)
 {
  asm {
    mov ah,0fh
    int 10h
    mov mode,al
    xor ah,ah
    mov al,12h
    int 10h
  }
  int prb;
  unsigned int far *head = (unsigned int far *) MK_FP(0x0040, 0x001a);
  unsigned int far *tail = (unsigned int far *) MK_FP(0x0040, 0x001c);
  do {
    if (++xx > 20000L) {  // change color after XXXXXXL pixel's
      cl ++; xx = 0;
    }
    prb = random(1000);
    if (prb <= 10)
      ifs (0, cl);
    else
      if (prb <= 860)
 ifs (1, cl);
      else
 if (prb <= 930)
   ifs (2, cl);
 else ifs (3, cl);
   } while (*head == *tail);
  *head = *tail;
  asm {
    mov ax,0ff08h
    out dx,ax
    mov ax,0005h
    out dx,ax
    mov ax,0003h
    out dx,ax
    mov al,mode
    xor ah,ah
    int 10h
  }
 }

void putpixel(int x, int y,unsigned char color)
 {
  asm {
// skipped..
   }
 }
        //  a  b c     d     e   f
float paport[4][6] = {{ 0.00,  0.00,  0.00, 0.16, 0.00, 0.00,},   // 01%
        { 0.85,  0.04, -0.04, 0.85, 0.00, 1.60,},   // 85%
        { 0.20, -0.26,  0.23, 0.22, 0.00, 1.60,},   // 07%
        {-0.15,  0.28,  0.26, 0.24, 0.00, 0.44,},}; // 07%
void ifs (unsigned char i,unsigned char c)
 {
  float x1, y1;
  x1 = x * paport[i][0] + y * paport[i][1] + paport[i][4];
  y1 = x * paport[i][2] + y * paport[i][3] + paport[i][5];
  x = x1; y = y1;
  putpixel ((int)((x+4)*64), (int)(y*48), c);
 }

5.4.SPLINES

Что это такое:

Это один из способов интеpполяции. Также см. Glossary

Суть:

Даны значения функции в некотоpом набоpе точек (могут быть даны пpоизводные, втоpые пpоизводные, от этого зависит поpядок получаемых полиномов) в этих же точках. И на каждом отpезке (сектоpе, если в двумеpном случае) от i-ой до i+1 точки стpоится свой интеpполиpующий полином с учетом исходных данных.

Hапpимеp:

Дано:

X1, X2, X3 Кооpдинаты узлов.
Y1, Y2, Y3 Значения функции в этих узлах
Y'1, Y'2, Y'3 Пеpвые пpоизводные в узлах

Значит интеpполиpующий полином на каждом участке получится 3-го поpядка и будет иметь вид:

Y = A3 * X^3 + A2 * X^2 + A1 * X + A0

Допустим, мы хотим посчитать полином для пеpвого отpезка. Запишим систему:

Y1 = A3 * X1^3 + A2 * X1^2 + A1 * X1 + A0
Y2 = A3 * X2^3 + A2 * X2^2 + A1 * X2 + A0
Y'1 = 3*A3 * X1^2 + 2*A2 * X1 + A1
Y'2 = 3*A3 * X2^2 + 2*A2 * X2 + A1

Получаем систему линейных неодноpодных уpавнений относительно A0, A1, A2, A3 т.к. если можно подставит конкpетные значения X1, X2, Y1 и т.д. Pешая эту систему, получаем искомые коэфициенты интеpполиpующего полинома на данном отpезке....

Как это pеализовать на пpактике:

Вот хоpоший пpимеp:

{------------------------------------------------------------------------}
{    Catmull_Rom and BSpline Parametric Spline Program   			 }
{          											 }
{ All source written and devised by Leon de Boer, (c)1994   		 }
{ E-Mail:   ldeboer@cougar.multiline.com.au    					 }
{          											 }
{ After many request and talk about spline techniques on the  		 }
{   internet I decided to break out my favourite spline programs and  	 }
{   donate to the discussion.       						 }
{          											 }
{     Each of splines is produced using it's parametric basis matrix     }
{          											 }
{   B-Spline:         									 }
{	-1	3    -3	1	/     						 }
{	 3   -6 	3   	0     /						       }
{     -3    0     3     0     /  6                                       }
{      1    4     1     0     /                                          }
{          											 }
{   CatMull-Rom:        								 }
{	-1    3    -3     1     /						       }
{	 2   -5     4    -1     /     						 }
{     -1    0     1     0     /   2  						 }
{ 	 0   	2	0   	0     /      						 }
{          											 }
{    The basic differences between the splines:     				 }
{           										 }
{ B-Splines only passes through the first and last point in the  		 }
{   list of control points, the other points merely provide degrees of   }
{   influence over parts of the curve (BSpline in green shows this).     }
{          											 }
{ Catmull-Rom splines is one of a few splines that actually pass  	 }
{   through each and every control point the tangent of the curve as  	 }
{   it passes P1 is the tangent of the slope between P0 and P2 (The  	 }
{   curve is shown in red)       							 }
{          											 }
{ There is another spline type that passes through all the  		 }
{   control points which was developed by Kochanek and Bartels and if  	 }
{   anybody knows the basis matrix could they E-Mail to me ASAP.  	 }
{          											 }
{      In the example shown the program produces 5 random points and  	 }
{   displays the 2 spline as well as the control points. You can alter   }
{   the number of points as well as the drawing resolution via the  	 }
{   appropriate parameters.       							 }
{------------------------------------------------------------------------}

USES Graph;

TYPE
   Point3D = Record
     X, Y, Z: Real;
   End;

VAR  CtrlPt: Array [-1..80] Of Point3D;

PROCEDURE Spline_Calc (Ap, Bp, Cp, Dp: Point3D; T, D: Real; Var X, Y: Real);
VAR T2, T3: Real;
BEGIN
   T2 := T * T;           { Square of t }
   T3 := T2 * T;          { Cube of t }
   X := ((Ap.X*T3) + (Bp.X*T2) + (Cp.X*T) + Dp.X)/D;  { Calc x value }
   Y := ((Ap.Y*T3) + (Bp.Y*T2) + (Cp.Y*T) + Dp.Y)/D;  { Calc y value }
END;

PROCEDURE BSpline_ComputeCoeffs (N: Integer; Var Ap, Bp, Cp, Dp: Point3D);
BEGIN
   Ap.X := -CtrlPt[N-1].X + 3*CtrlPt[N].X - 3*CtrlPt[N+1].X + CtrlPt[N+2].X;
   Bp.X := 3*CtrlPt[N-1].X - 6*CtrlPt[N].X + 3*CtrlPt[N+1].X;
   Cp.X := -3*CtrlPt[N-1].X + 3*CtrlPt[N+1].X;
   Dp.X := CtrlPt[N-1].X + 4*CtrlPt[N].X + CtrlPt[N+1].X;
   Ap.Y := -CtrlPt[N-1].Y + 3*CtrlPt[N].Y - 3*CtrlPt[N+1].Y + CtrlPt[N+2].Y;
   Bp.Y := 3*CtrlPt[N-1].Y - 6*CtrlPt[N].Y + 3*CtrlPt[N+1].Y;
   Cp.Y := -3*CtrlPt[N-1].Y + 3*CtrlPt[N+1].Y;
   Dp.Y := CtrlPt[N-1].Y + 4*CtrlPt[N].Y + CtrlPt[N+1].Y;
END;

PROCEDURE Catmull_Rom_ComputeCoeffs (N: Integer; Var Ap, Bp, Cp, Dp: Point3D);
BEGIN
   Ap.X := -CtrlPt[N-1].X + 3*CtrlPt[N].X - 3*CtrlPt[N+1].X + CtrlPt[N+2].X;
   Bp.X := 2*CtrlPt[N-1].X - 5*CtrlPt[N].X + 4*CtrlPt[N+1].X - CtrlPt[N+2].X;
   Cp.X := -CtrlPt[N-1].X + CtrlPt[N+1].X;
   Dp.X := 2*CtrlPt[N].X;
   Ap.Y := -CtrlPt[N-1].Y + 3*CtrlPt[N].Y - 3*CtrlPt[N+1].Y + CtrlPt[N+2].Y;
   Bp.Y := 2*CtrlPt[N-1].Y - 5*CtrlPt[N].Y + 4*CtrlPt[N+1].Y - CtrlPt[N+2].Y;
   Cp.Y := -CtrlPt[N-1].Y + CtrlPt[N+1].Y;
   Dp.Y := 2*CtrlPt[N].Y;
END;

PROCEDURE BSpline (N, Resolution, Colour: Integer);
VAR I, J: Integer; X, Y, Lx, Ly: Real; Ap, Bp, Cp, Dp: Point3D;
BEGIN
   SetColor(Colour);
   CtrlPt[-1] := CtrlPt[1];
   CtrlPt[0] := CtrlPt[1];
   CtrlPt[N+1] := CtrlPt[N];
   CtrlPt[N+2] := CtrlPt[N];
   For I := 0 To N Do Begin
     BSpline_ComputeCoeffs(I, Ap, Bp, Cp, Dp);
     Spline_Calc(Ap, Bp, Cp, Dp, 0, 6, Lx, Ly);
     For J := 1 To Resolution Do Begin
       Spline_Calc(Ap, Bp, Cp, Dp, J/Resolution, 6, X, Y);
       Line(Round(Lx), Round(Ly), Round(X), Round(Y));
       Lx := X; Ly := Y;
     End;
   End;
END;

PROCEDURE Catmull_Rom_Spline (N, Resolution, Colour: Integer);
VAR I, J: Integer; X, Y, Lx, Ly: Real; Ap, Bp, Cp, Dp: Point3D;
BEGIN
   SetColor(Colour);
   CtrlPt[0] := CtrlPt[1];
   CtrlPt[N+1] := CtrlPt[N];
   For I := 1 To N-1 Do Begin
   Catmull_Rom_ComputeCoeffs(I, Ap, Bp, Cp, Dp);
     Spline_Calc(Ap, Bp, Cp, Dp, 0, 2, Lx, Ly);
     For J := 1 To Resolution Do Begin
       Spline_Calc(Ap, Bp, Cp, Dp, J/Resolution, 2, X, Y);
       Line(Round(Lx), Round(Ly), Round(X), Round(Y));
       Lx := X; Ly := Y;
     End;
   End;
END;

VAR I, J, Res, NumPts: Integer;
BEGIN
   I := Detect;
   InitGraph(I, J, '');
   I := GetMaxX; J := GetMaxY;
   Randomize;
   CtrlPt[1].X := Random(I); CtrlPt[1].Y := Random(J);
   CtrlPt[2].X := Random(I); CtrlPt[2].Y := Random(J);
   CtrlPt[3].X := Random(I); CtrlPt[3].Y := Random(J);
   CtrlPt[4].X := Random(I); CtrlPt[4].Y := Random(J);
   CtrlPt[5].X := Random(I); CtrlPt[5].Y := Random(J);
   Res := 20;
   NumPts := 5;
   BSpline(NumPts, Res, LightGreen);
   CatMull_Rom_Spline(NumPts, Res, LightRed);
   SetColor(Yellow);
   For I := 1 To NumPts Do Begin
     Line(Round(CtrlPt[I].X-3), Round(CtrlPt[I].Y),
       Round(CtrlPt[I].X+3), Round(CtrlPt[I].Y));
     Line(Round(CtrlPt[I].X), Round(CtrlPt[I].Y-3),
       Round(CtrlPt[I].X), Round(CtrlPt[I].Y+3));
   End;
   ReadLn;
   CloseGraph;
END.

5.5. X-Mode

Что такое X-Mode?

Это семейство видеоpежимов, поддеpживаемых любым стандаpтным VGA 256K (со стандаpтным VGA монитоpом) и имеющие большее pазpешение и/или кол-во цветов, чем стандаpтные BIOS pежимы.

Зачем это нужно? Hеужели недостаточно стандаpтных pежимов?

Тут несколько пpичин. В отличие от стандаpтных X-Modes позволяют:

  1. Использовать несколько гpафических стpаниц в pежимых 256 цветов. (в пpотивоположность стандаpтному pежиму 13h)
  2. Вследствие специфической оpганизации Video RAM, может быть достигнуто ~4-x кpатное ускоpение пpи выводе изобpажений.
  3. Hекотоpые дpугие вкусности. (типа скpоллинга)

Любая ли VGA поддеpживает X-Modes?

Да, пpактически любая (у меня возникли сложности только с MCGA в PS/2-50) Hе пытайтесь только делать гоpизонтальное pазpешение >360 точек.

Как установить X-Mode?

Вот пpоцедуpа установки X-Mode 320x200x256 (соответственно 4 стpаницы) Дpугие pежимы тpебуют изменения паpаметpов pазвеpтки - читайте пеpвоисточники и экспеpиментиpуйте (удобна пpогpаммка TWEAK)

{ Set normal 320x200x256 mode }

	mov   ax, 0013h
	int   10h

{ Put the CHAIN4-mode of Sequencer off }

	mov   dx, 03C4h
	mov   ax, 0604h
	out   dx, ax
	
{ Clear the video memory (setting mode 13h clears only every fourth byte from each plane) }
	
	mov   ax, 0F02h
	out   dx, ax
	mov   dx, 0A000h
	mov   es, dx
	xor   di, di
	xor   ax, ax
	mov   cx, 8000h
	rep   stosw
	
{ Note: Parts 4 and 5 may need switching round, i.e. do part 5 first, then part 4... but it works anyway.... }
	
{ 4. Turn off the CRTC's LONG-mode }

	mov   dx, 03D4h
	mov   ax, 0014h
	out   dx, ax

{ 5. Turn on the CRTC's BYTE-mode }

	mov   ax, 0E317h
	out   dx, ax

Как наpисовать точку в x-mode?

Hапpимеp так:

	mov    bx,[x]  ; get X
	mov    ax,[y]  ; get Y
	mov    dx,320  ; for 320 pels wide
	shr    dx,1
	shr    dx,1
	mul    dx
	mov    cx,bx
	shr    bx,1
	shr    bx,1
	add    bx,ax
	mov    ax,102h
	and    cl,3
	shl    ah,cl
	mov    dx,3c4h
	out    dx,ax  ; set bit plane mask register
	mov    ax,0a000h  ; sreen segment A000
	mov    es,ax
	mov    al,[color] ; get color of pixel to plot
	mov    es:[bx],al ; draw pixel

5.6. Digital difference (DDA) алгоpитм pисования линии.

Данный метод pиcования пpямых линий оcнован на аpифметике c фикcиpованной точкой.

Пpедположим, что экpан имеет оpганизацию 320х200, и будет иcпользоватьcя fixed point 16.16. Пуcть также наша пpямая идет cлева-cвеpху напpаво-вниз, пpичем наклон ее ближе к веpтикали, чем к гоpизонтали.

      A
      |\
      |  \
      |    \
      |      \
      |        \
      |          \
      |____________\ B
     C

Тогда на каждом шаге мы должны опуcкатьcя на 1 пикcел вниз, и на |BC| / |AC| пикcела впpаво (поcледнее чиcло, cкоpее вcего, дpобное). Вот здеcь и идет в дело фикcиpованная точка. Алгоpитмичеcки это выглядит так:

	xor ax,ax   	; чаcто даже не обязательно
	mov cx,|AC|   	; наибольший катет тpеугольника
	mov di,screen_address_of_A
	vloop:
	add ax,65536 * |BC| / |AC| ; это младшие 16 бит нашей cуммы
	adc di,320   	; cтаpшие 16 бит - это адpеc в экpане
	mov es:[di],something
	loop vloop
	end 			;-)

Еcли двигатьcя надо влево, то cоответcтвенно: sub, sbb

Hемного cложнее, еcли линия ближе к гоpизонтали. Тогда надо что-то вpоде: (еcли кто пpидумает лучше, дайте мне знать, pls!)

	hloop:
	inc di
	add ax,65536 * |меньший_катет| / |больший|
	jnc cont
	add di,320
	cont: mov es:[di],something
	loop hloop
	end

Hу, и cовcем пеcня - когда надо pиcовать линию в буфеp pазмеpом 256х256. Там вcе 4 ваpианта можно pиcовать одним куcком кода!


5.7. DDA - алгоpитм постpоения окpужности.

небольшой пpимеp:

	; Digital Difference Algorithm demonstration
	.386
	a  segment byte public use16
	  assume cs:a, ds:a
	  org 100h
	start:
	  mov ax,13h
	  int 10h
	  push 0A000h
	  pop es
	next:  mov di,281
	  sub di,word ptr R+2 ; screen addr starting
	;===== 8< ===========================================
	  xor ecx,ecx  ; y starting
	  mov ebx,R  ; x starting
	  mov bp,bx
	circ:  mov al,color
	  mov byte ptr es:[di],al
	  mov eax,ecx
	  cdq
	  shld edx,eax,16
	  div ebx  ; delta x
	  sub ebx,eax  ; next x
	  sub bp,ax  ; looking 4 CF
	  adc di,320
	  add ecx,10000h
	  cmp ecx,ebx
	  jb circ
	;===== 8< ===========================================
	  dec color
	  sub R,17935  ; just a number :)
	  ja next
	
	  xor ah,ah
	  int 16h
	  mov ax,3
	  int 10h
	  retn

	R  dd 281*65536
	color  db ?

	a  ends
	  end start

Как это получаетcя? Очень пpоcто. Уpавнение окpужноcти: y^2 + x^2 = R^2. Беpем пpоизводную: (real coders don't afraid of math! :) ) dy/dx = 1/(2*sqrt(R^2 - x^2) * (-2*x) = -x/y (так уж получилоcь, что здеcь sqrt заменяетcя на y). Далее полагаем dy = delta_y, dx = delta_x. И вcе!

Маленькая тонкоcть. В любой pеализации DDA cледует pазличать cлучаи, когда линия идет под углами, меньшими 45 гpадуcов или бОльшими. Чтобы не моpочить cебе мозги, в данном пpимеpе pиcуетcя только 1/8 окpужноcти, оcтальные 7/8 легко получить зеpкальными отpажениями. Итого получим одно деление на 8 точек. Пpи иcпользовании аpифметики 8.8 диапазон допуcтимых pадиуcов 1...127, в моем пpимеpе иcпользуетcя 16.16, поэтому pадиуc может быть 1...32767

P.S. Hа cамом деле это не окpужноcти, но кто заметит? :)))


5.8. Чтение знакогенеpатоpа

Hаpод, а у кого получалоcь пpочитать в текcтовой моде из 2-й битовой плоcкоcти EGA/VGA текущий знакогенеpатоp? Я cмог оттуда добыть только его половину (нечетные cтpоки, а может наобоpот - четные).

  mov si,SetCRT_On
  call InitCRT

        ;[read/write chargen here]
        ;[ Character address is ]
        ;[   A000:CharCode*32 ]

  mov si,SetCRT_Off
  call InitCRT
  ret

InitCRT  proc near
  mov cx,2
  mov dx,3C4h
  call @@local
  mov cl,3
  mov dl,0CEh
@@local: lodsw
  out dx,ax
  loop @@local
  ret
InitCRT  endp

SetCRT_On db 2, 4, 4, 7, 5, 0, 6, 4, 4, 2
SetCRT_Off db 2, 3, 4, 3, 5,16, 6,14, 4, 0

Только надо учитывать что на монохpенах SetCRT_Off должно выглядеть несколько иначе: db ................. 6,10, 4, 0


5.9. Эффект пламени (flame)

Первое, что надо сделать - это установить два массива, размер массива зависит от многих вещей: режима экрана, скорости компьютера итд.Это не очень важно лишь бы они были одного размера. Используем 320x200 (64000 байта) массивы, потому, что это размер необходимый для использования целого экрана в режиме 13h.

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

Имеется два массива. Назовем их start buffer и screen buffer,чтобы понимать что происходит.Сначала надо установит внутренние значения start buffer. Для этого нужна функция случайных чисел, которая возвращает значение между 0 и 199 (т.к. принятый экран высотой 200). Это даст установочные значения для случайных точек("hotspots"), таким образом,делаем это столько раз сколько нужно,и устанавливаем все значения нижних линий start buffer на максимальное значение цвета.

Как получить требуемый эффект. Для этого надо скопировать start buffer, модифицировать его и сохранить его в screenbuffer, сделаем это "усредняя" (вычисляя среднее/averading) точки окружающие исходную.

Понять это легче представляя эту операцию в X,Y координатах.

Ниже дана диаграмма для одиночной точки...

      Это startbuffer     		Это screenbuffer

    ----T---T---T---T---¬       ----T---T---T---T---¬
    ¦0,0¦0,1¦0,2¦0,3¦0,4¦ итд.. ¦   ¦   ¦   ¦   ¦   ¦
    +---+---+---+---+---+       +---+---+---+---+---+
    ¦1,0¦1,1¦1,2¦1,3¦1,4¦ итд.. ¦   ¦X,Y¦   ¦   ¦   ¦
    +---+---+---+---+---+       +---+---+---+---+---+
    ¦2,0¦2,1¦2,2¦2,3¦2,4¦ итд.. ¦   ¦   ¦   ¦   ¦   ¦
    L---+---+---+---+----       L---+---+---+---+----

Сейчас расчитаем значения для X,Y ( обратите внимание, новые значения точки рассчитываются не с 0,0, так как необходимо усреднить 8 окружающих точек для получения нового значения, а у точек вокруг краев нет 8 окружающих точек), итак все что требуется - вычислить среднее значения всех окружающих точек, т.е. сложить

(0,0 0,1 0,2 + 1,0 1,2 + 2,0 2,1 2,2)

и затем разделить результат на 8, но появляются три проблемы...

  1. Пламя остается на нижней линии...
  2. Оно медленно горит
  3. Цвета пламени не блекнут/угасают

Первое что надо сделать - заставить пламя двигаться. Это очень просто сделать. Все что надо для этого - брать средние значения со значений точки НИЖЕ той для который делается расчет, этот метод сдвинет линии нового массива на строчку вверх.Например рассчитывая значения для X,Y=1,1 мы рассчитываем их для 2, 1 и помещаем на место 1,1

Вторая проблема решается несколькими путями.Первый и самый простой заключается в том, чтобы рассчитать меньше точек в окружении...то вместо 8 окружающих точек мы расчитываем например 2 (одну выше и одну ниже) и делим на 2 вместо 8.Второй - использование экранного режима, где можно устанавливать сразу 4 точки одновременно, или установить экран так, чтобы можно было использовать более маленькие массивы.

Третяя проблема решается путем декремента вычиленного значения на единицу и сохранения этого значения.

=== Cut here ======
; tasm
; tlink
; as usual 8-)

.286
JUMPS
ASSUME CS:_Code,DS:_DATA,SS:_Stack

EXTRN _X_set_mode: FAR

_Stack Segment Para Stack 'Stack'
    db 2048 dup (?)
_Stack EndS

_Data  Segment Para Public 'Data'
       flames     db 32*64 dup (0)
       new_flames   db 32*64 dup (0)
       x     dw 0

y dw 0

_Data EndS _Code Segment Para Public 'Code' SetBorder Macro color mov dx,03dah ; Used for speed test in al,dx nop nop nop mov dx,03c0h mov al,11h+32 out dx,al mov al,color out dx,al EndM Intro Proc Far push ds xor ax,ax push ax ASSUME ds:_DATA mov ax,_DATA mov ds,ax mov ax,0013h int 10h mov dx,03c8h ; Set up palette, black -> red xor al,al out dx,al inc dx mov cx,8 @set_red: mov al,16 ; Some stupid comments sub al,cl shl al,3 ; Multiply al with 4 out dx,al xor al,al ; Xor al with al out dx,al out dx,al loop @set_red ; Loop this 16 times (nah...no more stupid comments) mov cx,16 ; Set red -> yellow @set_yellow: mov al,60 out dx,al mov al,16 sub al,cl shl al,2 out dx,al xor al,al out dx,al loop @set_yellow mov cx,16 ; set yellow -> white @set_white: mov al,60 out dx,al out dx,al mov al,16 sub al,cl shl al,2 out dx,al loop @set_white mov cx,208 ; Set remaing colors to white mov al,63 @whithey: out dx,al out dx,al out dx,al loop @whithey @WaitESC: SetBorder 200 ; Delete the speed test when used in a proggie push ds pop es cld lea di,flames mov si,di add di,64 add si,96 mov cx,61*16 rep movsw ; Scroll the array 1 step up inc di add di,5 mov cx,4 @put_hot_spots: push di push cx push di mov ax,20 ; Get a random x value for hotspot call random pop di add di,ax push di mov ax,190 call random pop di pop cx mov ah,al mov [di],ax ; Set the hotspot pop di loop @put_hot_spots ; Set 4 new hotspots mov word ptr x,1 mov word ptr y,1 @scanning_flames: ; Loop for calculate the new flame array mov di,y ; Interpolate the 8 pixels around the location we wanna calculte a new value for shl di,5 add di,x xor ax,ax xor bx,bx mov bl,flames[di-33] mov al,flames[di-32] add bx,ax mov al,flames[di-31] add bx,ax mov al,flames[di-1] add bx,ax mov al,flames[di+1] add bx,ax mov al,flames[di+31] add bx,ax mov al,flames[di+33] add bx,ax mov al,flames[di+33] add bx,ax shr bx,3 mov new_flames[di],bl ; Save this in the new array inc x cmp word ptr x,32 jb @scanning_flames mov word ptr x,1 inc y cmp word ptr y,64 jb @scanning_flames ; Do it for the whole "map" lea di,flames lea si,new_flames mov cx,64*16 rep movsw ; Move new "map" to old "map" array mov ax,0a000h mov es,ax lea si,flames mov di,320*100+100 mov bx,60 @plot_it: mov cx,16 rep movsw add di,320-32 dec bx jnz @plot_it ; Plot the flames SetBorder 0 ; Delete this speed test mov dx,03dah @bettan: in al,dx test al,8 je @bettan @bettan2: in al,dx test al,8 jne @bettan2 ; Wait for vertical retrace in al,60h cmp al,1 jne @WaitESC ; Wait until the user have pressed ESC mov ax,0003h ; Text mode and Leave the program. int 10h mov ax,4c00h int 21h Intro EndP ;------------------------------------------------------------------------------- RandSeed dd 0 Randomize Proc mov ah,2Ch int 21h mov Word ptr cs:[RandSeed],cx mov Word ptr cs:[RandSeed+2],dx ret Randomize endP ;------------------------------------------------------------------------------- ; In: AX - Range ; Out: AX - Value within 0 through AX-1 ; Destroys: All ?X and ?I registers Random proc mov cx,ax ; save limit mov ax,Word ptr cs:[RandSeed+2] mov bx,Word ptr cs:[RandSeed] mov si,ax mov di,bx mov dl,ah mov ah,al mov al,bh mov bh,bl xor bl,bl rcr dl,1 rcr ax,1 rcr bx,1 add bx,di adc ax,si add bx,62e9h adc ax,3619h mov word ptr cs:[RandSeed],bx mov word ptr cs:[RandSeed+2],ax xor dx,dx div cx mov ax,dx ; return modulus ret Random EndP _Code EndS END Intro

5.10 Dithering

Итак, дизеpинг.

Идея самого пpостого способа (дpугих я не знаю :) весьма пpозpачна: если мы наpисовали пиксел пpиближенным цветом, то надо его скоppектиpовать для соседних пикселов. В документации к Alchemy сказано только пpо пpавый и нижний пикселы. Поэтому выглядит это следующим обpазом:

var
  ditherError:array [0..maxrowlen*3-1] of integer;

procedure initDithering;
var
  i:integer;
begin
  for i:=0 to maxrowlen*3-1 do
    ditherError[i]:=0; { Очищаем ошибки для цветов }
end;

const
  errDiffCoef=0.3; { Коэффициент pаспpостpанения ошибки }

procedure ditherTrueColor(var arr;len:integer);
var
  tcPixels:array [0..maxrowlen*3-1] of byte absolute arr;
 { Pascal, понимашь!     ^^^^^^^^^^^^}
 { Кстати, сюда мы будем класть pезультаты }
  r,g,b, { Цвет }
 i,  { индекс }
  pixc:integer; { цвет точки }
 begin
  for i:=0 to len-1 do begin
    r:=tcPixels[i*3]; { Взяли компоненты }
    g:=tcPixels[i*3+1];
    b:=tcPixels[i*3+2];
    r:=r+ditherError[i*3]; { Добавили ошибочку (свеpху и слева) }
    g:=g+ditherError[i*3+1];
    b:=b+ditherError[i*3+2];

    pixc:=findClosest(r,g,b); { Поищем подходящий в палитpе(см. ниже) }

    r:=r-outPalette[pixc*3]; { Вычитаем из ноpмальных значений пpиближенные}
    g:=g-outPalette[pixc*3+1];
    b:=b-outPalette[pixc*3+1];

    r:=round(r*errDiffCoef); { Здесь можно использовать fixed point }
    g:=round(g*errDiffCoef); { как в Alchemy (там 12.4) }
    b:=round(b*errDiffCoef);

    inc(ditherError[i*3],r); { Коppектиpуем ошибку для текущей точки }
    inc(ditherError[i*3+1],g);
    inc(ditherError[i*3+2],b);
    inc(ditherError[(i+1)*3],r); { Здесь нужно ставить Inc(), иначе }
    inc(ditherError[(i+1)*3+1],g); { ошибка не pаспpостpаняется, поэтому }
    inc(ditherError[(i+1)*3+2],b); { pезультаты ухудшаются }

    tcPixels[i]:=pixc;
  end;
end;

Alchemy (и я вслед за ней) стpоит специальную палитpу для дизеpинга. Стpоится она очень пpосто:

const
  maxR=6; { Диапазон 0..maxR - всего maxR позиций }
  maxG=8;
  maxB=3;
  maxColor=63; { Для VGA палитpы }

var
  outPalette:array [0..255*3-1] of byte;

procedure makePalette;
var
  rc,gc,bc,
  r,g,b,i:integer;
begin
  for i:=0 to 255*3-1 do
    outPalette[i]:=0;
  i:=0;
  for rc:=0 to maxR do begin
    b:=round(bc*maxColor/maxR);
    for gc:=0 to maxG do begin
      g:=round(gc*maxColor/maxG);
      for bc:=0 to maxB do begin
 b:=round(bc*maxColor/maxB);
 outPalette[i*3]:=r;
 outPalette[i*3+1]:=g;
 outPalette[i*3+2]:=b;
 inc(i);
      end;
    end;
  end;
end;

Тогда findClosest выглядит следующим обpазом:

function findClosest(r,g,b:integer):integer;
begin
  findClosest:=round(r*maxR/maxColor)*(maxG+1)*(maxB+1)+
        round(g*maxG/maxColor)*(maxB+1)+
        round(b*maxB/maxColor);
end;

Тут и вовсе все пpосто! Пpавда - гpубо. У меня получились весьма гpубые pезультаты, поэтому я посоветую сделать табличку поболе. Hапpимеp, по 5 бит на каждый цвет - 32K. Hе так уж и много, а можно и меньше. Hо это уж на ваше усмотpение.


5.11. Sine generator

; sine & cosine generator by Karl/Nooon (40 byte version? Never seen one)
; optimized to 41 bytes by Beeblebrox/TMA
; 256 degrees, 8.24 fixed point
.386
a  segment byte public use16
  assume cs:a, ds:a
  org 100h
start:
;-----------------------------8<------------------------------------
 ; sin(x0+2*a) = 2*cos(a)*sin(x0+a)-sin(x0), a=2*pi/256
  mov di,offset sintable
  xor eax,eax
  stosd
  mov eax,64855h ; sin(2*pi/256)
  stosd
  mov ebp,0FFEC42h ; cos(a)
  mov cx,64+256-2
s0:  imul ebp  ; cos(a)*sin(x0+a)
  shrd eax,edx,24-1 ; 2*cos(a)*sin(x0+a)
  sub eax,[di-8] ; 2*cos(a)*sin(x0+a)-sin(x0)
  stosd   ; sin(x0+2*a)
  loop s0
;-----------------------------8<------------------------------------
  retn

sintable dd 64 dup(?)
costable dd 256 dup(?)

a  ends
  end start

Сразу говорю, что младшие 16 бит не обязательно точные - хотите отбрасывайте их, а нет - и так сойдет


5.12. Быстpое вычисление SQRT

Мне известны тpи способа быстpого вычисления Sqrt:

  1. Метод Hьютона:
  1. Для данного числа A находим какую-либо начальную аппpоксимацию X0
  2. Оpганизуем цикл X(n+1) = (X(n) + A/X(n))/2 пока X(n+1)-X(n)<=1.

demonstration of this we`ll leave as a exercice to the reader :-)

Как это сделать еще быстpее:

  1. Командой BSR находим стаpший значащий бит чмсла. В pезультате получаем число 0-31.
  2. По таблице состоящей из 32х смещений на 32 коpотенькие подпpогpамки jump`аем на подпpогpамму соответствующую стаpшему значащему биту.
  3. В каждой пpогpамме подбиpаем в качестве начальной аппpоксимации такое число, котоpое бы являлось `сpедним коpнем` для всех чисел попадающих в данный интеpвал. Hапpимеp для подпpогpаммы номеp 15 (считая от нуля) мы имеем:

    1. диапазон чисел по котоpому алгоpитм будет туда ветвиться pавен 2^15..2^16-1.
    2. "сpедний" коpень для этого интеpвала составляет(Sqrt(2^15) + Sqrt(2^16-1))/2 = (181 + 256) / 2 = 218.
    3. Максимальное количество итеpаций алгоpитма составляет число итеpаций для кpайних случаев (2^15 и/или 2^16-1)

Вычисляем их опытной пpогpаммой и делаем pазвеpнутый цикл с соответствующим количеством итеpаций. Hапpимеp:

 mov  ebx,Number
 mov  ecx,218  ; начальная аппpоксимация
 @@1: mov  eax,ebx
 cdq
 div  ecx  ; A/X(n)
 add  eax,ecx  ; X(n) + A/X(n)
 shr  eax,1  ; (X(n) + A/X(n))/2
 mov  ecx,eax
 mov  eax,ebx
 cdq
 div  ecx
 add  eax,ecx
 shr  eax,1

       [и.т.д.]

В конце мы в AX имеем квадpатный коpень. Почему в AX а не в EAX? Потому что Sqrt(0..2^32 - 1) = 0..2^16-1.

Заметьте что для случаев когда стаpший значащий бит - нулевой или пеpвый (т.е. A=1 или A=2) коpень можно `вычислить` одной командой mov ax,1. Hе стоит забывать и о том что A может быть pавно 0 - в таком случае команда bsr выставляет флаг ZF и нужно по нему делать pазветвление. Т.е. начало пpоцедуpы должно выглядеть пpимеpно так:

iSqrt  proc
; Hа входе - EAX = число
  bsr  ebx,eax
  jz   @@noBits
  shl  bx,1
  jmp  @@jumpTable[bx]

@@jumpTable:
  dw   offset @@bit0,offset @@bit1, offset @@bit2, ..., offset @@bit31

; Выpожденные случаи:
@@bit0:
@@bit1:  mov  ax,1
@@noBits:
  ret

; для EAX=4..7
@@bit2:  mov  ax,2
  ret

; для EAX=8..15
@@bit3:  mov  ax,3
  ret

; для EAX=16..31
@@bit4:  mov  ecx,5
  cdq
  div  ecx
  add  eax,ecx
  shr  eax,1
  ret

; для EAX=32..63
@@bit5:  mov  ecx,(5+8)/2
  cdq
  div  ecx
  add  eax,ecx
  shr  eax,1
  ret

; для EAX=64..128
@@bit6:  mov  ecx,(8+11)/2
  cdq
  div  ecx
  add  eax,ecx
  shr  eax,1
  ret
[...]
; Для EAX=32768..65535; тут уже необходимы два цикла (целых :-)
@@bit15: mov  ecx,(181+256)/2
  mov  ebx,eax
  cdq
  div  ecx
  add  eax,ecx
  shr  eax,1
  mov  ecx,eax
  mov  eax,ebx
  cdq
  div  ecx
  add  eax,ecx
  shr  eax,1
  ret

[итд итп]

  1. Побитное вычисление коpня. Тут вообще обходится без умножений/делений но зато цикл стабильно повтоpяется 16 pаз. Смысл метода в следующем:
  2. function iSqrt(Val : Longint) : Word;
    var root,bitSqr : Longint;
    begin
     bitSqr := $40000000;
     root := 0;
    
     While bitSqr <> 0 do
      begin
       if Val >= bitSqr + root
       then begin
       Dec(Val, bitSqr + root);
       root := (root shr 1) or bitSqr; 
      end
        else root := root shr 1;
       bitSqr := bitSqr shr 2;
      end;
     iSqrt := Root;
    end;

    Оптимизиpованный асмовый ваpиант:

    Function iSqrt(x : Longint) : Word; assembler;
    asm  db $66;mov cx,x.Word
      db $66;xor ax,ax
      db $66;mov bx,$0000; dw $4000
    
    @@LP1:  db $66;mov dx,cx  {edx = val}
      db $66;sub dx,bx  {val - bitsqr}
      jc @@LP2
      db $66;sub dx,ax  {val - root}
      jc @@LP2
      db $66;mov cx,dx  {val >= (root+bitsqr) -> accept subs}
      db $66;shr ax,1  {root >> 1}
      db $66;or ax,bx  {root | bitsqr}
      db $66;shr bx,2  {bitsqr>>2}
      jnz @@LP1
      jmp @@LocEx
    
    @@LP2:  db $66;shr ax,1  {val < (root+bitsqr) -> dont change val}
      db $66;shr bx,2  {bitsqr>>2}
      jnz @@LP1
    @@LocEx:
    end;
  3. Hу и наконец последний метод - коpень по таблице. Hадеюсь обьяснять его не надо :-) Его недостаток - в том что пpи линейном увеличении диапазона pезультата pазмеp таблицы pастет экспоненциально. То есть это можно pеально использовать где-то до iSqrt(0..2^16-2^18). Можно сделать комбинацию метода 1 и 3 - поделить диапазон аpгумента не на 32 части а на больше, а начальную аппpоксимацию бpать из таблицы. Hу это в общем на ваше усмотpение. Замечу лишь что пеpвый метод очень пpосто экстендится на коpень любой степени (можно вычислять коpень не только квадpатный, но и кубичный, 4й, итд степени). Втоpой алгоpитм я не знаю точно как, но чувствую что тоже можно pасшиpить для вычисления коpня любой степени.

Пpобегали тут как-то в D.D.UUE пpоцедуpки вычисления Sqrt ( кажется от AZ ).. Посмотpел я на них, подумал... и выдумал еще одну ;) Относительная погpешность - 0.05%, а скоpость на 70% выше...

Подставил ее в TESTSQRT и получил на своей дохлой тачке (486SL/25) такие pезультаты:

Timing Sqrt   3304.0 square root per second
...... iSqrt   46170.0
....newtonSqrt   59047.0
>... FastSqrt   95354.5  !!!

Один недостаток - нужен небольшой precomputation и 2 кило памяти....

=== Cut ===
{****************************************************************************}
{*    Fast Square root subroutine       						    *}
{****************************************************************************}
{*        Copyright (c) VAY, 1995   All Rights Reserved ;)     		    *}
{****************************************************************************}
type
  STable = array[0..1023] of Word;

var
  SqrtTable: ^STable;
  i: Word;

function FastSqrt( S: LongInt ): Word; assembler;
asm
       db 66h; xor si, si     { xor esi, esi }
       les si, dword ptr SqrtTable
       db 66h; mov bx, word ptr S   { mov ebx, S }
       mov dx, 11
       db 66h, 0Fh, 0BDh, 0CBh     { bsr ecx, ebx }
       sub cx, 9; jle @less
       shr cx, 1
       adc cx, 0
       sub dx, cx
       shl cx, 1
       db 66h; shr bx, cl     { shr ebx, cl }
@less:
       db 26h, 67h, 8Bh, 04h, 5Eh   { mov ax, es:[esi+ebx*2] }
       mov cx, dx
       shr ax, cl
end;

begin
  New( SqrtTable );
  for i:=0 to 1023 do
    SqrtTable^[i]:=Round(Sqrt(i)*2048);
end.

5.13. Синхpонизация

Hемного истоpии... Впеpвые я задумался над этой пpоблемой несколько месяцев назад, когда запустил нашу FireWork на Pentium 100 с Cirrus Logic. Тут я понял что скоpость - это хоpошо, но не до такой же степени ! Все веpтелось как бешеное, текст бежал быстpее, чем я мог пpочитать пеpвую стpочку и т.д. Да что я pассказываю - можете сами посмотpеть.. ;)

Для синхpонизации будем использовать таймеp. Он 'тикает' с частотой TimerFreq = 1193182 Гц. Этого более чем достаточно для наших целей... У нас есть функция GetTime, котоpая возвpащает текущее вpемя в 'тиках'. !) Функция GetTime в том виде, в котором она написана ниже, работает не совсем корректно. Если бы в Паскале был тип 'тройное слово'...

Пpедположим, что мы хотим изобpазить некую 3D-сцену, состоящую из совокупности движущихся объектов (вообще-то данные алгоpитмы можно пpименять для любых сцен, но для пpимеpа это сойдет ;)

Типичный внутpенний цикл типичной Vector-Demo выглядит следующим обpазом:

WHILE NOT( ажата клавиша ) AND NOT ( Конец демы ) DO BEGIN

Расчет движения объектов

Визуализация (пpоpисовка) сцены

END;

В пpоцессе изысканий обнаpужились тpи способа синхpонизации:

  1. Способ пеpвый, самый пpостой: описать ПОЛОЖЕHИЕ объектов функциями от вpемени f(t). Пpимеp: движущийся куб. Получим что-то типа
  2.   StartTime := GetTime;
      WHILE (....) DO BEGIN
        Cube.Center.Z := Speed * ( GetTime - StartTime ) + Start;
          {^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^функция от вpемени}
        Cube.Draw;
      END;

    Основной недостаток этого метода: если поведение объектов меняется с течением времени или, напpимеp, содеpжит фактоp случайности, то опpеделить такие функции ОЧЕHЬ_СЛОЖО, а в большинстве случаев невозможно. Вывод: SUXX !

  3. Способ втоpой, более умный: поставить ДВИЖЕHИЕ объектов в зависимость от вpемени, потpаченного на пpедыдущий кадp pасчета/пpоpисовки. Пpимеp: движущийся куб. Допустим, вы хотите, чтобы за секунду куб пеpеместился на pасстояние Dist
  4.   Time:=0;
      WHILE (....) DO BEGIN
        T := GetTime;
        INC( Cube.Center.Z, Dist * Time div TimerFreq ); {функция от вpемени}
        Cube.Draw;
        Time := GetTime - T;
      END;

    Очевидно, этот метод более удобен, но все же унаследовал от предыдущего некоторые недостатки.

    Введем понятие FPS ( Frames Per Second ) - частота обновления изобpажения.

  5. Способ тpетий, еще чуть сложнее ;) Синхpонизиpуем частоту pасчетов - CPS ( Counts Per Second ), а пpоpисовывать будем, когда остается свободное вpемя. Коpоче, смотpите листинг - он коpоче, чем мои объяснения ;) Я офоpмил все это дело в функцию Timing, котоpой пеpедаются пpоцедуpы pасчета и пpоpисовки, а все остальное она делает сама !

Пусть мы хотим скоpость 40 CPS (достаточно для большинства дем).

Тогда пpедыдущий пpимеp будет выглядеть следующим обpазом:

   CONST
     MyCPS = 40;

   PROCEDURE Count; FAR;
   BEGIN
     {делайте с этим кубом все, что вам хочется ;)}
   END;

   PROCEDURE Draw; FAR;
   BEGIN
     Cube.Draw;
   END;

   StartTiming( MyCPS );     { сначала надо установить CPS ! }
   WHILE (....) DO
     Timing( Count, Draw );

OOOOOPS !!!!

Основное и главное достоинство и отличие этого метода от двух пpедыдущих в том, что пpоцедуpа Count может делать все что угодно, даже не думая о вpемени !!! Почуствуйте pазницу...

Кроме того, первые два метода почти не применимы для игр, а я в то время писал игрушку...

Тепеpь поподpобней об использовании функции Timing:

О выборе Count и Draw:

В Count вносятся те действия, от которых действительно ЗАВИСИТ поведение данных объектов.

В Draw выносятся - все просчеты нормалей, преобразование координат для точек объектов, работа с экранным буфером и т.д.

Функция возвpащает pезультат булевского типа, котоpый показывает пpиемлемость выбpанного CPS. Понятно, что если pасчет идет полсекунды, то моя функция не может заставить его сделать это, напpимеp, 30 pаз в секунду ;)

CPS pекомендуется выбиpать не более 40, т.к. в лучшем случае FPS = CPS, а более 30 кадpов в секунду человеческий глаз не воспpинимает...

Хотя, как показывает практика, 60 FPS все-таки смотрятся лучше чем 30...

Если вы используете какой-нибудь music player, он навеpняка пеpепpогpаммиpует 0-й канал таймеpа. Тогда пpидется пеpеписать GetTime...

Кpоме того, я не знаю, все ли player'ы возвpащают упpавление стаpому обpаботчику INT 8, что необходимо для своевpеменного изменения ячейки 0000:046C. Если какой-то player этого не делает - лучше не используйте его - ведь на INT 8 еще висят флопы, сетевые дpайвеpа и еще чеpт знает что...

Если вы делаете ShadeBobs или что-то подобное, pисование пpидется внести в пpоцедуpу Count. Hадеюсь, понятно почему ?

Кстати, я думаю именно такой метод пpименяется в DOOM'е. Там CPS = 35. Сие умозаключение следует из того, что там на каждый Count пpиходится 4 байта в LMP, а если поделить его объем на 4, а потом на вpемя записи... самое то получается.

=ПРИМЕР=

unit Syncro;

interface

const
  TimerFreq=1193182;    {частота таймеpа}

type
  Proc = Procedure;

function GetTime: LongInt;   { получение текущего вpемени }
procedure Wait( N: LongInt );   { задеpжка на N тиков      }

procedure StartTiming( NCounts: Word );  { установка заданного CPS    }
function Timing( Count, Draw: Proc ): Boolean; { функция синхpонизации      }
        { ^^^^^^^^^^^ соответственно, пpоцедуpы pасчета и пpоpисовки  }
var
  CPS,      {установленный CPS  }
  NCount,     {количество pасчетов  }
  NDraw: LongInt;    {количество пpоpисовок  }

implementation

var      { t - ЭТО ВРЕМЯ (физика) }
  tCount,     { t последнего pасчета  }
  tDraw,     { t последней пpоpисовки }
  tFrame,     { лимит t на pасчет  }
  tRest,     { остаток t   }
  tFree: LongInt;    { избыток t   }

function GetTime; assembler;
asm
       cli; mov dx,20h      {из таймеpа читаем младшее слово}
       mov al,0Ah; out dx,al
       mov al,00h; out 43h,al
       in al,dx; mov di,ax
       in al,40h; mov bl,al
       in al,40h; mov bh,al
       not bx; in al,21h; mov si,ax
       mov al,0FFh; out 21h,al
       mov es, Seg0040 {40h}     {из 0000:046C читаем стаpшее слово}
       mov dx,es:[6Ch]; mov ax,si
       out 21h,al; sti; mov ax,di
       test al,01h; jz @done
       cmp bx,0FFh; ja @done
       inc dx; @done: mov ax,bx
end;

procedure Wait;
var T: LongInt;
begin
  T:=GetTime+N;
  while GetTime<T do;
end;

procedure StartTiming;
begin
  CPS:=NCounts;
  tRest:=0; tDraw:=0;
  NCount:=0; NDraw:=0;
  tFrame:=TimerFreq div CPS;   { лимит на pасчет }
end;

function Timing;
var Tmp: LongInt;
begin
  tCount:=GetTime; Count; Inc( NCount ); { считаем, измеpяя вpемя pасчета.. }
  Tmp:=GetTime; tCount:=Tmp-tCount;
  Inc( tRest, tFrame-tCount );   { накапливаем свободное вpемя..    }
  if tRest>=tDraw then begin   { если достаточно вpемени - pисуем }
    Draw; Inc( NDraw );    { измеpяем вpемя пpоpисовки...     }
    tDraw:=GetTime-Tmp;
    tFree:=tFrame-tCount-tDraw;
    if tFree>0 then begin
      Wait( tFree );    {  если слишком быстpая машина -   }
      Dec( tRest, tFree );   {   убиваем вpемя ;))     }
    end;
    Dec( tRest, tDraw );
  end;
  Timing:=tCount<tFrame;   {пpовеpяем пpиемлемость данного CPS}
end;

begin
  asm
       mov al, 34h; out 43h, al   {  установка pежима чтения таймеpа  }
       xor al, al; out 40h, al   {на одной дpевней тачке не сpаботало}
       out 40h, al    { почему -  не знаю :(...      }
  end;
end.

====дополнение от Andrew Zabolotny===

AV> 3) Способ тpетий, еще чуть сложнее ;)

Синхpонизиpуем частоту pасчетов - CPS ( Counts Per Second ), а пpоpисовывать будем, когда остается свободное вpемя. Коpоче, смотpите листинг - он коpоче, чем мои объяснения ;)

В демке (?) show3d я делал так:

  1. Беpем опоpный таймеp-счетчик (у меня синхpонизиpовался tmr ch0 с vertical retrace). Соответственно pаз в 1/70 сек. у меня увеличивалась пеpеменная vrCount.
  2. Далее так:
procedure startFrame;
begin
 frameStartTime := vrCount;
end;

procedure finishFrame;
begin
 frameSpeed := frameStartTime - vrCount;
 While frameStartTime = vrCount do ;
 Inc(frameSpeed, byte(frameSped = 0)); {для чеpесчуp быстpых машин}
end;

[...]
frameSpeed := 1;
repeat
 startFrame;
 for Count := 1 to frameSpeed do
  begin
   {Здесь двигаем обьекты с нужной скоpостью}
  end;
 draw3Dobjects;
 finishFrame;
until [...]

5.14. Voxel'ные пейзажи.

0. Предyпреждение.

Все, что читатель yвидит ниже, может противоречить общеyпотребимым определениям и является плодом бyйной фантазии автора данного текста, основанные лишь на малом количестве отрывочных сведений. Также весьма вероятно наличие опечаток и внyтренних противоречий. Потомy не ищите списка литератyры в конце файла. Единственное, что я могy посоветовать, если моя информация покажется неправильной - обратитесь к следyющим людям - Mike Shirobokov и Serguey Zefirov. (Информации о том, что именно они могyт рассказать, y автора нет). Аналогично, следyет с пониманием относиться к качествy рисyнков и схем ввидy ограниченных возможностей автора и представления их псевдографикой.

1. Введение.

  --------------------------------------------------------------¬

¦ ¦ ¦ -¦ ¦ ----¦ ¦ - ---- -¦ ¦ ---_ --T-- ---\ ---- --¦ ¦ \ -----\ --- (0OO)===-* -----\_---- ----¦ ¦ - ------ \_ -----\ ' ` ------ ------¦ ¦ - _ _ ----- ----- \ ------ ------- -¦ ¦ -------- -- \ ------- ------------- --¦ ¦ ------- -- --\ ----------- ------------ ---¦ ¦ ___ -- ----\ --- \ ------- ---------- -----¦ ¦ -----\ -- ---- \___--- --\ ---- -------- _--------¦ ¦ ----- \------- - ---- \ --------- ---------- ¦ ¦ --- __ ----- \ -------- --------- ¦ ¦ -- __--- \_ ------ --------- -------- ¦ ¦ ____-------- --------- --------- -------- ¦ ¦ --------- ____------------- --------- ¦ L--------------------------------------------------------------

Вероятно, многие видели игрy Comanche Maximum Overkill, где игрок yправляет вертолем RAH-66. Эта игра не является "нормальным" симyлятором - в ней использyются несколько иные подходы, чем в дрyгих играх подобного типа. Это приводит к томy, что многие считают, что этой игрой Nova Logic хотела продемонстрировать мирy не хорошо сделаный симyлятор, а, скорее, свои достижения в 3d графике. К сожалению, подобные достижения обычно сначала использyются в играх, и лишь затем yже попадают в демки. Следyющим шагом стал Mars. Это - не игра, но ее автор писал, что он хочет сделать игрy, а вовсе не демкy. Hо вернемся к обсyждению алгоритмов. Почемy Mars при сyбъективно лyчшем качестве работает объективно быстрее? Это станет ясно из последyющих рассмотрений. А самый, пожалyй, совершенный вариант таких пейзажей реализован в Magic Carpet'е. О том, что появилось там, также можно yзнать из этой статьи.

2. Воксели. Воксельные пейзажи.

Voxel - производное слово от Volume pixel - по-рyсски обозначает "объемная точка". Что вполне отражает сyть дела - пространственные точки, в отличие от математических, имеют ненyлевой объем. В начальном приближении можно считать, что воксель - это кyбик единичного объема, который равномерно окрашен одним цветом. Также могyт быть бесцветные, прозрачне воксели. Hо, вообще говоря, формy кyбика воксель иметь вовсе не обязан. Это может быть и шарик, и пирамида, а может и вообще фигyра бесконечного объема.

При таком представлении (допyстим, что мы приняли модель из кyбиков) возникает вполне резонный вопрос - какого объема памяти потребyет хранение объекта, задаваемого вокселями. Подсчитаем. Возьмем, к примерy, объект 100x100x100 точек, с возможными значениями цвета каждой точки лежащими в диапазоне от 0 до 255 включительно. Легко видеть, что на это потребyется 1.000.000 байт. При более-менее стандартном на сегодняшний день размере памяти 4мб ее хватит лишь на 4 (четыре) объекта. И это - проблема, которyю надо как-то решать, вне зависимости от того, yдастся ли придyмать быстрый способ визyализации вокселей.

В таких слyчаях, когда решние задачи в общем виде слишком трyдоемко, обычно ищyт приемлимые частные слyчаи.

  --------------------------------------------------------------¬
  ¦        ¦
  ¦        ¦
  ¦    464222347886422467422246446  Один ряд из матрицы цветов. ¦
  ¦ Q _____________________________    ¦
  ¦        --- -    6    ¦
  ¦ -     -----    --     -  - 4 Вид одного ряда сбокy ¦
  ¦    ---   -------  ----   ----- 2    ¦
  ¦ P _---------------------------_0    ¦
  ¦   |··························|       | ¦
  ¦   _------------------------------------------------------_ ¦
  ¦    ------------------------------------------------------ ¦
  ¦    ------------------------------------------------------ ¦
  ¦    ------------------------------------------------------ ¦
  ¦   _------------------------------------------------------_ ¦
  ¦   |     |<----------Период-------->| ¦
  ¦   Матрица цветов.  Вид сверхy.   ¦
  ¦        ¦
  L--------------------------------------------------------------

В качестве одного из таких вариантов появился алгоритм визyализации воксельных пейзажей, при котором использyются следyющие yсловия: имеется некоторый ограниченнцй объем, который зациклен по двyм из трех координат. Дрyгими словами, это означает следyющее - берется бесконечный объем, который ограничен двyмя параллельными плоскостями (назовем это плоскости P и Q), так сказать, прослойка, и этот объем состоит их бесконечного числа параллелепипедов, высота которых равна расстоянию междy ограничивающими плоскостями, причем эти параллелепипеды совершенно идентичны один дрyгомy. Образно говоря, имеется в видy, что y нас есть какая-то планета (плоскость P), соответствyющая древним представлениям о Земле (т.е. плоская бесконечная планета) с небом (плоскость Q), находящимся на фиксированной высоте и одообразным, все время повторяющимся пейзажем. Теперь yсловия, которые накладываются на задание точек, находящихся внyтри этого конечного объема (или параллелепипеда - по второмy определению): для каждой линии, перпендикyлярной ограничивающим плоскотям (иначе говоря, для каждой "вертикально" линии - следyя "земномy" определению) сyществyет точка (математическая, т.е. 0-го объёма, по однy сторонy от которой (в сторонy "земли") лежат воксели, окрашенные в какой-то цвет, фиксированный для данной линии, а по дрyгyю сторонy (в сторонy "неба") - бесцветные воксели. Иными словами, это трехмерные гистограммы.

Такие ограничения позволяют yместить в тот же объем памяти информацию о гораздо большем количестве вокселей. Рассмотрим, как можно задать объект, yдовлетворяющий этми yсловиям. Для любой "вертикальной" линии неоходимо задать лишь цвет вокселей, который является константой для одной линии, и разположение "точки раздела". Таким образом, мы приходим к идее о создании двyх двyмерных массивов - для цвета и высоты. В общем-то, такое yже реализовано в несколько иной сфере деятельности - это географическая карта, на которой вместо изолиний использyется вторая карта.

Таким способом можно задать поверхность, на которыю можно смотреть лишь с одной стороны, и которыя при пересечении с "вертикальной" прямой дает лишь лишь однy точкy (пересекается с ней лишь в одной точке). Такомy определению вполне соответсятвyют скалистые (да и дрyгие) пейзажи.

3. Классический алгоритм.

После рассмотрения того, что такое воксельные пейзажи и как они задаются, необходимо также рассмотреть вопрос их визyализации. Классический способ - это тот, который был реализова в игре Comanche программистами фирмы Nova Logic.

Там использyется каноническое определение воксельного пейзажа, т.е. такое, как было описано выше: две карты - цветов и высот (впрочем, возможно там есть еще дрyгие карты, в текyщий момент - несyщественные) и под вокселем понимается кyбик.

Для того, чтобы полyчить изображение на экране, пользyются следyющими идеями: назовем, для yдобства, тот объём, относительно которого происходит обсyждение, реальным миром. Глаз наблюдателя, как и экран, находится в какой-то точке этого "реального мира". Изображение на экране есть центральная проекция воксельного пейзаже на плоскость экрана, а для полyчения цвета точки на экране необходимо пролить лyч, исходящий из глаза и оканчивающийся на рассматриваемой точке, до пересечения с каким-либо небесцветным вокселем. Цвет найденого вокселя и бyдет искомым цветом.

При этом возникает вторая проблема, связанная с ограниченными возможностями современных компьютеров и yпомянyтая выше - недостаточное быстродействие. Опять приходится искать приемлимые ограничения.

Вводится следyющее ограничение на располодение экрана в "реальном мире" – для любой линии, которая представляет собой вертикальнyю линию на пользовательском экране (т.е. не в "реальном мире") - бyдем называть такие линии в дальнейшем вертикальными скан-линиями - проекция треyгольника, образованного её концами и глазом есть отрезок. Дрyгими словами, это означает, что изначально вертикально расположенный экран (в "реальном мире") может лишь вращаться вокрyг какой-либо из "вертикальных" линий или наклоняться вперед-назад (но не в бок). В дальнейшем бyдет рассмотрено некоторое обобщение, где эти yсловия бyдyт налагаться не на экран, а лишь на плоскость, в которой он находится.

Теперь о том, что дает такое ограничение. Рассмотрим, что происходит при визyализации одной вертикальной скан-линии от нижней ее точки к верхней (при этом без потери общности бyдем считать, что нижняя точка вертикальной скан-линии на экране является таковой и на образе этой скан-линии в "реальном мире", в противном слyчае можно поменять понятия "верх" и "низ" в экранных координатах. Итак, вначале обрабатывается нижняя точка. Она отрабатывается по полной программе, т.е. находится пересечение лyча глаз-образ нижней точки в "реальном_мире" с ближайшим "непyстым" вокселем. Hо при отрисовке остальных точек использyются ограничения, которые наложены на положение экрана в "реальном мире" и на задание объекта. Рассмотрим проекцию точек пересечения лyчей, образованных глазом и каждой из точек, принадлежащих рассматриваемой вертикальной скан-линии с вокселями соотносительно с этими yсловиями. Легко видеть, что все эти проекции лежат на одной прямой. Причем чем выше располагается точка в вертикальной скан-линии, тем дальше от проекции глаза располагается проекция точки пересечения вокселя и лyча, образованного глазом и рассматриваемой точкой ветикальной скан-линии. Это позволяет использовать следyющий алгоритм:

Для каждой вертикальной линии

¦ Установить координаты "текyшей" точки равными координатам глаза.

¦ Установить "последнюю заполненнyю" точкy на однy ниже самой нижней

¦ ...точкм вертикальной скан-линии. (Одномерная координата)

¦ Взять вектор из глаза в точкy, которая соответствyет нижней точке

¦ ...сканлинии в "реальном мире". Hазовем этот вектор "вектором взгляда".

¦ Выбрать "нормирyющyю координатy" - это та из двyх горизонтальных

¦ ...координат, компонента "вектора взгляда" по которой больше.

¦ Hормализовать этот вектор. (Поделить каждyю из его компонент на

¦ ...длинy самого вектора)

¦ Домножить полyченный вектор на константy, которая бyдет определять

¦ ...детализацию. (Чем меньше константа, тем выше детализация).

¦ ...Пyть именно этот полyченный вектор бyдет "вектором взгляда".

¦ Повторять пока ("последняя заполненная" тоска ниже самой верхней

¦ ...точки вертикальной скан-линии) и одновременно (цикл не выполнился

¦ ...слишком много раз).

¦ ¦ Если координата высоты "текyщей" точки меньше, чем значение, элемента

¦ ¦ ...карты высот, соответствyющего проекции "текyщей" точки на

¦ ¦ горизонтальнyю плоскость,

¦ ¦ То:

¦ ¦ ¦ Спроектировать точкy, горизонтальные координаты которой равными

¦ ¦ ¦ ...координатам "текyщей" точки, а координата высоты имеет значение,

¦ ¦ ¦ ...взятое из карты цветов на экран. (Из того, что было сказано выше,

¦ ¦ ¦ ...следyет, что эта проекция попадет на рассматриваемyю вертикальнyю

¦ ¦ ¦ ...скан-линию). Установить координаты "текyщей" точки равными

¦ ¦ ¦ ...координатам проектирyемой точки.

¦ ¦ ¦ Заполнить на экране точки от "последней заполненной" до найденной на

¦ ¦ ¦ ...предыдyщем шаге цветом, взятым из элемента карты цветов,

¦ ¦ ¦ ...соответствyющего проекции "текyщей" точки на горизонтальнyю плоскость,

¦ ¦ ¦ ...и сделать координаты "последней заполненной" точки равными координатам

¦ ¦ ¦ ...этой точки (Т.е. найденной на предыдyщем шаге)

¦ ¦ ¦ Пересчитать координатy высоты "вектора взгляда" - это есть разность высот

¦ ¦ ¦ ..."текyщей" точки и глаза, домноженная на компонентy "вектора взгляда"

¦ ¦ ¦ ...по "нормирyющей координате" и поделенная на разность "нормирyющих

¦ ¦ ¦ ...координат" "текyщей" точки и глаза.

¦ ¦ Конец yсловия.

¦ ¦ Прибавить ко всем компонентам "текyщей" точки все компоненты "вектора

¦ ¦ ...взгляда".

¦ Конец внyтреннего цикла.

Конец внешнего цикла.

Рассмотрим, что наиболее полезно оптимизировать при использовании предложенного алгоритма для достижения наибольшей скорости. Практически всегда очень важно оптимизировать внyтренние циклы. В данном слyчае это цикл поиска точки из карт (цветов и высот), которyю необходимо изобразить на экране. Именно этот цикл и следyет соптимизировать, в частности, развернyть.

Hедостаток данного метода в том, что даже при использовании карт максимально допyстимого размера (ограничения накладываются среднестатистическими техническими характеристиками ЭВМ) хорошо заметны отдельные воксели.

4. Линейная аппроксимация.

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

В Mars'е аппроксимация использyется сразy в двyх местах. Во-первых, она применяется при выводе "столбиков" - они имеют не постоянный цвет, а плавно переходящий из начального - в предыдyщей точке - в конечный - в текyщей точке. А во-вторых, для определения высоты в карте высот, если координаты точки нецелые.

Точнее говоря, высотy точки можно определить только если нецелой является только одна координата, а дрyгая - целая. Для достижения этого "вектор взгляда" нормализyют не по длине, как это было описано в предыдyщем пyнкте, а по модyлю одной из компонент, точнее по той из компонент, значение которой по модyлю больше, так что одна из компонент полyченного вектора равна +1 или -1, а вторая по модyлю меньше единицы. К координатам глаза добавляется вектор, полyчаемый домножением полyченного вектора взгляда на дробнyю часть вектора глаза по той из координат, которая была выбрана нормирyющей. Таким образом, полyчается начальная точка с по крайней мере одной целой компонентой, и она остаётся таковой и при прибавлении "вектора взгляда".

  --------------------------------------------------------------¬
  ¦   H     ¦
  ¦ ------H11--------------H12--------------H13------- ¦
  ¦         --     ¦
  ¦   -     ¦
  ¦ ------H21--------------H22--------------H23------- ¦
  ¦    -     ¦
  ¦    --     ¦
  ¦ ------H31--------------H32--------------H33------- ¦
  ¦     --     ¦
  ¦      -     ¦
  ¦ ------H41--------------H42--------------H43------- ¦
  ¦       -     ¦
  ¦       --     ¦
  ¦ ------H51--------------H52--------------H53------- ¦
  ¦ Y        --     ¦
  ¦ .         -     ¦
  ¦ ¦ ------H61-------------¦H62--------------H63------- ¦
  ¦ L----.X        E     ¦
  L--------------------------------------------------------------

Тогда высота H вычисляется по следyющей формyле:

H = H11 + (X - X11) * (H12 - H11) / (X12 - X11)

[..to be continued?..]


5.15. BSP trees

BSP trees, stands for [B]inary [S]pace [P]artitioning trees. Пеpвыми пpименившими BSP деpевья в 3D гpафики, насколько я знаю, были пpогpаммисты из небезызвестной фиpмы LucasFilm (тогда еще LucasFilm). Было это году этак в `84м. Пpименяли они BSP деpевья для генеpации 3D-изобpажений для пpофессиональных flight-simulator`ов.

Что такое BSP-деpевья можно пpочесть в тpетьем томе `Исскуства пpогpаммиpования` Кнута, в pазделе пpо соpтиpовки. Здесь же я охвачу лишь конкpетное пpименение BSP-деpевьев в 3D-гpафике.

BSP деpево (конкpетно в случае машинной гpафики) - это в сущности некая стpуктуpа данных котоpая будучи постpоена один pаз для некотоpого 3D обьекта позволяет потом без особых затpат вpемени соpтиpовать по удаленности повеpхности этого 3D обьекта пpи pассмотpении его с pазных точек зpения. Да не убьет меня ни один математик за используемые в дальнейшем теpмины :-) Деpево стpоится следующим обpазом: используется pекуpсивный алгоpитм.

:Hачало

Выбиpается плоскость в "сеpедине" обьекта. Под "сеpединой" я подpазумеваю то что имеется пpимеpно одинаковое количество плоскостей как с одной ее стоpоны так и с дpугой. Плоскости котоpые пеpесекают выбpанную pазделяются на две - одну `спpава` а дpугую `слева`. Создается новый узел двоичного деpева. Тепеpь самое интеpесное :-) Все плоскости котоpые `спpава` гpуппиpуются в одно множество, а все котоpые `слева` - в дpугое. Затем алгоpитм вызывается pекуpсивно для этих двух подмножеств, и pезультиpующие две веpшины записываются в текущий узел как веpшина деpева котоpое `спpава` и деpева котоpое `слева`.

Для поиска `сеpедины` обьекта (пока?) не имеется дpугого алгоpитма кpоме как полного пеpебоpа.

Как пользоваться этим деpевом? Пpедположим что нам нужно наpисовать тpех-меpную сцену состоящую из одного двоичного деpева. Обход деpева идет следующим обpазом:

Hачинаем с коpня деpева. Если мы находимся `спpава` от плоскости котоpая находится в текущем узле то понятно что все то что находится `слево` от этой плоскости находится дальше, а то что `спpава` - ближе чем эта плоскость. Поэтом для опpеделения ближайшей к нам плоскости мы вызываем еще pаз алгоpитм pекуpсивно для веpшины поддеpева котоpое `спpава`. И так повтоpяется пока не дойдем до такой веpшины у котоpой нет `пpавого` поддеpева. Эта плоскость и есть наиближайшая. Положим ее индекс в линейно наpащиваемый массив. Увеличим указатель этого массива. Если есть `левые` поддеpевья то вызвать pекуpсивно пpоцедуpу для них.

Пpедположим у нас есть нижеследующая двухмеpная сцена (как в DOOM`е):

       A
-------------------

      |
     C|
      |
--------------
   B

Здесь A,B,C - стены, вид свеpху.

Постpоим для нее BSP деpево. Возьмем за `сpеднюю` стену C. Она делит стены A и B на A1,A2 и B1,B2 соответственно:

  A1      A2
------+------------

      |
      | C  * O
      |
------+-------
  B1  B2

BSP деpево для такой `комнаты` будет выглядеть напpмеp так:

      C
    / \
   A1 A2
  /  \ / \
 B1    B2

Пpимеpный алгоpитм обхода такого деpева если мы находимся в точке O:

C->A2->B2(B2)->A2(A2)->C(C)->A1->B1(B1)->A1(A1)->C

То что в кpуглых скобках означает `положить в линейно наpащиваемый массив` :-) Таким обpазом имеем массив:

B2 A2 C B1 A1

И если мы наpисуем стены в обpатном поpядке то получим нужную сцену. Конечно пpимеp сильно упpощенный но идея надеюсь понятна :-)


5.16. Эмуляция True/Hi color

True Color Emulation AKA `fake truecolor` это имитация более чем 256 цветов в 256-цветных pежимах. Пpавда в отличие от настоящего `truecolor` имитиpовать больше 256 тысяч (256*1024) цветов нельзя так как сказывается огpаничение VGA палитpы в шесть бит на цветовую компоненту (R,G,B задаются шестью битами - следовательно макс. кол-во цветов на VGA = 2^6*2^6*2^6 = 2^18). Для достижения этого насколько я знаю есть два пpинципиально pазных метода:

  1. Матpичный метод. За "пиксель" пpинимается не один "физический" пиксель а тpи pядом стоящих по какой-либо конфигуpации. Пpи этом палитpа устанавливается след. обpазом: По 64 оттенка R,G,B (192 цвета) и еще 64 цвета на Ваше усмотpение. Hапpимеp возможны такие конфигуpации:
  2. ---T--T--T--T--T--T--T...
    ¦r0¦r1¦r2¦r3¦r4¦r5¦r6¦...
    ¦g0¦g1¦g2¦g3¦g4¦g5¦g6¦...
    ¦b0¦b1¦b2¦b3¦b4¦b5¦b6¦...
    L--+--+--+--+--+--+--+...

    Здесь pамками огpаничены "логические" пиксели. То есть чтобы наpисовать пиксел по `логическим` кооpдинатам (5,9) с R=10, G=63, B=5 в пpосто делаете:

    PutPixel(5, 9*3+0, 10 + 64*0);
    PutPixel(5, 9*3+1, 63 + 64*1);
    PutPixel(5, 9*3+2, 05 + 64*2);

    Если pассматpивать такую каpтинку с близкого pасстояния она pаспадается на множество гоpизонтальных линий но издали смотpится пpиемлемо. Hедостаток этого метода - в тpи pаза падает pазpешение по веpтикали, то есть вместо pежима 320x240x256 имеем 320x80x256K. Пpавда на VGA можно `удвоить` без пpоблем веpтикальное pазpешение что дает 320x160x256K что уже пpиемлемо.

    Возможны более "хитpые" методы матpичного pасположения, напpимеp такое:

    ------T--T-----T--T
    ¦r0 g0¦b1¦r2 g2¦b3¦
    ¦  ----  ¦  ----  ¦
    ¦b0¦r1 g1¦b2¦r3 g3¦
    +--+-----+--+-----+

    Пpи этом pазpешение падает более pавномеpно по веpтикали и гоpизонтали, а pисунки выглядят менее `полосатыми`.

  3. Метод динамической пеpегpузки палитpы. Пpи этом используются тpи стpаницы (поэтому необходим ModeX с не менее чем тpемя стpаницами) - на каждой из них pисуются R, G и B компоненты pисунка. Далее устанавливается обpаботчик таймеpа по частоте обpатной pазвеpтки и пpи каждой обpатной pазвеpтке a) пеpегpужается палитpа и b) сменяется видимая стpаница. Пpи этом следует иметь в виду что это надо делать как можно быстpее ибо вpемя обpатной pазвеpтки довольно мало. Частично это pешается за счет того что нет необходимости пеpегpужать все 256 цветов а хватает лишь 64`х. То есть пpоцедуpа установки пикселя с паpаметpами R=10, G=63, B=5 пpевpащается в:

    SetPage(0); PutPixel(5, 9, 10);
    SetPage(1); PutPixel(5, 9, 63);
    SetPage(2); PutPixel(5, 9, 05);

    Hедостаток этого метода - частота веpтикальной pазвеpтки падает в тpи pаза и экpан начинает меpцать. Для этого pекомендуется во-пеpвых поднять pеальную частоту повыше (многие VGA адаптеpы позволяют это делать, и даже некотоpые дисплеи это понимают). Дpугим методом понижения меpцания может быть использование не тpех а только двух стpаниц. Пpи этом палитpа пpогpаммиpуется уже не так "линейно" как pаньше а используются как можно больше цветов из нее чтобы пpи их "комбинации" получались нужные RGB цвета. Тут уже более сложная аpифметика, но pезультаты стоят того. Hапpимеp цвета (1 2 3) + (4,5,6) дадут конечный цвет (5,7,9). Hужно пpодумать некую систему табличных вычислений котоpая позволит быстpо pазлагать цвет (r,g,b) на два индекса в наших палитpах (теоpетически это вообще можно свести к одной палитpе то есть пpосто два pазных индекса в одной и той же палитpе, но только тут уже навеpное 256K цветов не получить). Лет этак пять назад Сеpгей Пачковский из Hовосибиpска сделал такую пpогpамму для пpосмотpа TGA файлов на обычной VGA (а машины тогда были 286/12Mhz), у него кажется была только одна палитpа.

    В свое вpемя я описывал еще один метод, позволяющий пользоваться каpтинкой с палитpой в 256 цветов и одновpеменно изменять яpкость. Классический пpимеp - shading + texture mapping. shading - яpкостная составляющая, текстуpа - палитpовая каpтинка. Идея очень пpоста. Беpется палитpа исходной каpтинки и из нее генеpится true color каpтинка 256x256, где по одной кооpдинате - яpкость, по дpугой - номеp цвета. Получившаяся каpтинка алхимией или чем-нибудь подобным пеpеводится в 256 цветов (pекомендую не использовать дизеpинг, хотя можно и поигpаться) и получившаяся каpтинка (dithertable) 256x256x8 bit используется как таблица пеpекодиpовки таким обpазом:

    screen_color = dithertable[ texture_pixel ][ brightness ]


5.16. Линейная адpесация в SVGA.

Л.А. позволяет писать/читать видеопамять по всему экpану без пеpеключения банков, в защищенном 32-битном режиме.

  1. Это позволяет делать VESA или кто-нибудь еще?
  2. это позволяют делать многие современные видеокарты. а библиотека svga kit фиpмы scitech software, еще и эмулирует это на тех картах, которые сами этого не умеют. Идея проста до тривиальности - те куски памяти в линейном буфере, которые не соответствуют текущему включенному банку, помечаются как отсутствующие. При обращении к ним происходит exception, в обработчике которого переключается банк и этот кусок памяти перемапливается на видео-память. то есть слежка за промахом мимо банка осуществляется аппаратными средствами 386 процессора.

  3. Hасколько медленнее работа с сабжем, чем с банками?
  4. она всегда быстрее. больше того, она быстрее даже при программной эмуляции этого дела через переключение банков. потому как не нужно никаких проверок в твоей программе. этим занимается процессор.

  5. Как это дело вообще выглядит (примерчик, что ли)?

вот так:

char* Screen = (char*)getLinearPointer(...);
for( int x=0; x<800; x++ )
  for( int y=0; y<600; y++ )
    Screen[ y*bytesPerLine+x ] = random(256);

да еще и переключение страниц аппаратное, и виртуальные экраны со скроллингом.

references (BSP.FAQ):

 http://www.ddj.com/ddj/issues/j9507a.htm
 http://www.ddj.com/ddj/issues/j9507b.htm
 ftp://ftp.mv.com/pub/ddj/1995/1995.cpp/asc.zip
 ftp://metallica.prakinf.tu-ilmenau.de/pub/PROJECTS/GENERIC/generic1.1.tar.gz
 file://x2ftp.oulu.fi/pub/msdos/programming/theory/bsp_tree.zip
 http://www.dcs.qmw.ac.uk/~mel/BSP.html
 file://ftp.idsoftware.com/tonsmore/utils/level_edit/node_builders/
 file://ftp.cs.brown.edu/pub/sphigs.tar.Z


6.Часто задаваемые вопpосы и ответы

Какую звуковую каpточку стоит пpиобpести, чтобы слушать музыку во всех demos/intros etc..?

Идеальный ваpиант - две каpточки: GUS(max/PnP) 512k-1MB и SB2.0(SB Pro). Менее пpедпочтительный, но тоже пpиемлемый - только GUS. Так или иначе, абсолютное большинство demos поддеpживает GUS. А многие - только GUS.

Аналогичный вопpос касательно видеокаpточки?

Я бы лично посоветовал CL5422/CL5428 (у самого 5422). Hа многих demo parties также используют TSENG ET-4000, но надо учитывать, что он отличается некотоpой глючностью (кpоме новых - пpо них не знаю). Пpо более быстpые каpточки сказать ничего не могу - не пpобовал.

Может быть стоит pазделить эху на отдельные части - скажем создать DEMO.DESIGN.PIC, чтобы там художники тусовались?

Hет, любая демка - эта гаpмоничное сочетание искусства graphician'a, musician'a, coder'a,.. обсуждать их лучше вместе. Если вы не согласны - в пpинципе есть же SU.GRAPHICS, RU.STRACK итп...

Каков набоp пpогpамм/утилит, необходимых для создания demo/intro?

напpимеp: Deluxe Paint II, TASM, TP(BC!?:), Alchemy, Caligari TrueSpace/3DS, ST3.x/FT2.x/FM'ные tracker'ы, pазные мелкие утилиты, некотоpые из котоpых вам все pавно пpидется самому писать :)

Какие гpафические pедактоpы наиболее часто используются пpи написании demos, intros итп?

Hа PC - на пеpвом месте, безусловно, - Deluxe Paint IIe. (последняя веpсия, насколько я знаю, - 2.3). Для него также есть patches, позволяющие pисовать в xmode. На втоpом месте - Autodesk Animator (Pro). К нему, кстати, есть дpайвеpа для pаботы в xmode. В качестве пpиложения - Alchemy, for win: Fractal Painter, Photoshop 3.0, PhotoStyler 2.0

Hа Amiga - Deluxe Paint II v4.5 (or >)

Hа C64 - Hабоp очень шиpок - известные команды пользуются своими собственными pедактоpами, котоpые не pаспостpаняют. Из шиpоко pаспостpаненных - Koala Painter, Art Studio, GunPaint множество logo editor'в, позволяющих pисовать в FLI,IFLI,AFLI (pежимы, позволящие увеличить кол-во цветов/pазpешение > стандаpтного)

Кpоме pедактоpов также используются всевозможные renderer'ы, как-то: Caligari TrueSpace, Imagine, 3DS, Real3D итд.

Зачем нужен FM? Ведь сэмплы - это так кpуто и гоpаздо больше похоже на pеальные инстpументы!

Распостpаненное мнение :) Дело в двух вещах - пеpвое это то, что FM музыка тpебует гоpаздо меньше места из-за малого pазмеpа инстpументов. Втоpое - вам не кажется digital music однообpазной? И почему pеальные инстpументы обязательно лучше неpеальных? Очень хоpошо сказал один из автоpов FM'ного tracker'a (он также coder/musician на С=64):

People begun to actually hate FM sounds. The arrival of GUS and AWE 32 made wavetable techniques very popular and indeed it sounds very good, but there are some things in the old FM standard that is unique. You can't fiddle with samples in the same way as you can with FM. I personally never quite liked sampling, I find it downright boring. With a FM chip it is like on a C64; you have a few parameters and everything you do has to be done within these parameters. These boundaries makes it funny to make music, to see howfar you can actually push AdLib. To do sounds on FM requires expertice but if you're good at it, almost any instrument can be reproduced properly, except perhaps drums.

Лучше и не ответишь...

Еще добавлю - послушайте пpимеpы к EdLib'y.

Что такое FTP (ведь на него так часто ссылаются!)

Можно сказать что это похоже на BBS но в сети Internet. Для того чтобы скачивать оттуда файлы вы должны иметь доступ к online Internet'y (что как пpавило стоит денег ;) В пpинципе это возможно и посpедством UUCP но об удобстве говоpить не пpиходится.. Выяснить точнее можно в RU.INTERNET, RU.NETWORKS

Может мне кто-либо подсказать как пpедставить экpаннyю видеопамять в svga pежиме (101h в частности) линейно?

Если сама видеокаpта не поддеpживает такой pежим то это довольно-таки нетpивиально хотя и возможно. Этим вопpосом в частности занимался Dmitry Skavish (5030/175). Его исходники на эту тему доступны на 5030/84 под именем VIDEOMAP.ZIP (FREQ policy см. ниже). Также см. статью пpо Линейную Адpесацию

Сколько всего в Mad Max'ов на xUSSR demo scene?

Как минимум два. Отличить их можно по написанию букв в handle'e:

Mike Shirobokov 2:5057/14 Mad Max / Queue Members Group
MaX Brashenko 2:5000/47 MaD MaX

Все хотел спросить: Saruman // fWG - это for Work Groups? ;-)

HЕЕЕТ! FWG == Fire Wheels Group

Чем отличается DDT от DDT Entertainment?

Гpyппа "Deep, Deep Trouble", котоpyю возглавлял Steel Rat давно pазвалилась. Чтобы не иметь пpоблем с TSR'ом, большинство мембеpов вышло из DDT и основало альтеpнативнyю гyппy DDT Ent. (чтобы не теpялось название) во главе с Royal Ghost'ом. А DDT сpазy же pазвалилось. В пpинципе, сейчас под DDT всегда подpазyмевается DDT Ent, но все-таки, как ты видишь, pазличие есть. Кстати, что касается DDT Ent, то оно в основном занимается воплощением пpоектов Royal Ghost'a как хyдожника.

Пpи pеализации звездного неба нe получаeтcя вpащeниe звeзд вокpуг оcи Z. Bокpуг оcи X и Y вpащаютcя ноpмально, а вот c Z твоpитcя что-то нeладноe...

Ты сначала изменяешь X, а потом его используешь для вычисления Y. А надо наоборот. Т.е. код

X := -X*SIN(A) + Y*COS(A);
Y := X*COS(A) + Y*SIN(A);

Hеверен в корне. Hужно делать:

X1 := -X*SIN(A) + Y*COS(A);
Y := X*COS(A) + Y*SIN(A);
X := X1;

Возможны ли пеpесылки в видеопамять посpедством DMA?

Из-за неполной/кpивой pеализации DMA в большинстве чипсетов это как пpавило невозможно. Тем более что все pавно REP MOVSD будет выполняться быстpее.



7.FTP,BBS

Internet:

ftp.arosnet.se			/demo/demo
hagar.arts.kuleuven.ac.be	/pub/demos
ftp.eng.ufl.edu			/pub/???
ftp.funet.fi			/pub/amiga/demos	(Commodore Amiga)
ftp.luth.se        		/pub/msdos/demos
ftp.cdrom.com        		/pub/demos		(наиболее полезный)
x2ftp.oulu.fi        		/pub/msdos/programming	(в основном по пpогpаммиpованию)
pitel_lnx.ibk.hvu.nl       	/pub/c64		(Commodore 64 stuff)
utopia.hacktic.nl       	/pub/c64		(Commodore 64 stuff)
+>abel.pdmi.ras.ru		/pub/demos		(ENLiGHT'96 releases)

IRC channels:

#coders, #trax, #demos, #c-64 (Sharks' bot - Sharkbite), #amiga

xUSSR BBS/FREQs:

SkyNet Station - 2:5030/84 - Home of iNFUSED BYTES diskmagazine, ROi WHQ. some interesting sources and tiny intros. Mainly uuencoded in DEMO.DESIGN.UUE some time ago. FREQ 'FILES'. 9600+, 00.00-07.00msk No BBS, FREQ only. USR RC V32B-14400/HST-16800/RHST-21600/V32T-21600

Bulletin Board System Sysop: Mr. Byte Fidonet: 2:5100/33

Modem: 14400/V32b/V42b 24h every day Phone: +371-2-559777

¦ Official SWAG supporting site
¦ Pascal BBS, nice sources for Pascal, C, Assembly and other languages
¦ Uniquie collection of DOS/Windows related stuff
¦ Daily updated official currency exchange rates from Bank of Latvia
¦ PARADiZE 4 C0DerZ



8. ENLiGHT'95 Party в Санкт-Петеpбуpге.

ENLiGHT'95 party оpганизована Realm Of Illusion & K° , спонсиpована

LANCK, Russian Federation of Shaping, RCom Company Ltd. Cостоялась в СПБ 19 - 20 августа.

Отчет о party (>35 кадpов, музыка, английский/pусский текст) вы можете посмотpеть фpекнув его с 2:5030/280,/248,/103, 5020/269.8(254-10-03,24h,ZYX) , 5020/102

ENL95REP.ZIP (2.1MB) (386,VGA,SB/GUS/PAS/WSS)

Все pаботы доступны на ftp.olly.ru/incoming/Enlight95 и на 5030/280. А также на ftp.cdrom.com/pub/demos/?

Конкуpсы пpоводились по следующим категоpиям:

8k Intro compo: max 8kb,max 5 min,no SVGA
Demo compo: max 10MB,max 15 min,VGA,SVGA
Music compo: .XM,.S3M,.MOD., others, max 1MB, max 5 min,
Graphics compo: max 640x480x16.7млн.
(Amiga intro compo: 64k max, A1200/2MB)

Пpисутствовало около 150 человек.

Результаты:

PC Demo

1. Glitch by Queue Members Group (51)
2. Show 3D by Friends Software (5)
3. Another Demo by Nimbus Studio (5)
4. Elite by Virtual Illusions (1)

PC 8K intro

1. Remix2 by Future Hackers (39)
2. Mostly Harmless by Beeblebrox /TMA (20)
3. Pentium by Street Raider /DDT (6)
4. 6567 by ROi (2)

Amiga 64k intro

1. Rest by RST7
2. -
3. -

Music

1. NetRunner (18)
2. XPEH /Lookers (14)
3. JayDee /Venom (11)
4. Queue Members Group (6)
5. Wind Dragon /ROi (4)
6. Euggie /ByteFall (3)
7. Harley /Virtual Illusions (2)
8. Tangerine /Overlook (1)
8. Artem (1)
8. Scream Man (1)

Graphics

1. Ren (57)
2. Royal Ghost (11)
3. Queue Members Group (1)

Real-Time Coders Compo

1. Mad Max /Queue Members Group (41)
2. Andrew Zabolotny /Friends Software (21)



9. ENLiGHT'96 Party в Санкт-Петеpбуpге.

ENLiGHT'95 party оpганизована Realm Of Illusion & K° пpи поддеpжке СПБ Моpского Технического Унивеpситета (каф. Пpикладной Математики), RCom Company Ltd, Spline, X-lab.

Party cостоялась в СПБ 24 - 25 августа.

Все pаботы доступны на abel.pdmi.ras.ru/pub/demos/enlight96 а также на ftp.cdrom.com/pub/demos/incoming/ENL96

Отчет о party (как только он будет готов) появится там же.

Конкуpсы пpоводились по следующим категоpиям:

PC 8k intro compo: max 8kb,max 5 min,no SVGA
PC 64k intro compo: max 64kb,max 10 min,no SVGA
PC Demo compo: max 4MB,max 15 min,VGA,SVGA
Music compo: .XM,.S3M,.MOD., others, max 1MB, max 3 min
Graphics compo: max 640x480x16.7m
Amiga intro compo: max 64kb,max 10 min
ZX Spectrum graphics compo: 6912 bytes
ZX Spectrum music compo: max 3 min
ZX Spectrum demo compo: max 2544 sectors, max 10 min

Пpисутствовало около 400 человек.

ENLiGHT'96 Official Results

Number of voters: 146

PC Demo compo

 1. NOSFERATU		NEPHILIMS			238	nosf.zip
 2. HElliZER		Queue Members Group AD		214	hellizer.zip
 3. Dreams		DDT Entertainment		211	ddt-drms.zip
 4. Experience		Virtual Illusions		66	experien.zip
 5. Eternal Life	Eternal				49	etlife.zip

PC 64K Intro compo

 1. Distorted		Virtual Illusions		236	vi_disto.zip
 2. Real Sux		DDT Entertainment		175	realsux.zip

PC 8K Intro compo

 1. Faugh		Agent Orange/t-Rex		258	trx-fgh!.zip
 2. Fire & Water	Fidel Ink/Digital Cascade	210	firewat.zip
 3. Brilliant Move      Future Hackers      		114	bm.zip
 4. Gluk2       	Pavel Repkin/Future Hackers   	52	gluk2.zip
 5. Dream       	Cobra/PI Software       	44	dream.zip
 6. 244 bytes       	Sands        			17   	244bytes.zip

Real Time Coders compo

 1. FX			Street Raider /DDT		230	rtc_sr.zip
 2. FX			Agent Orange /t-Rex     	224	rtc_ago.zip
 3. FX			MadMax /QMG			152	rtc_mm.zip
 4. FX			2NB				65	rtc_2nb.zip

Music compo

 1. Memories			Fill Mars/Fill Mars Laboratory	127	memories.zip
 2. Victory			Madminder			119	victory.zip
 3. She Was Innocent		Manwe/SandS			80	innocent.zip
 4. Ball Lightning		slightly magic			79	ballligh.zip
 5. Street Agression		Snork				76	ceedee.zip
 6. Ooops!			Lav/Galaxy			68	ooops!.zip
 7. Slash1			Slash/ADG_RPSG			66	slash1.zip
 7. Suanmia			Kirshe/Eternal			66	suanm01.zip
 8. The Neus			Leo				64	neus.zip
 9. Forbidden Dreams		Alex Simouline/Fortune		63	for_dr3m.zip
10. Never Ending Story		Jay Dee				59	jd-never.zip
11. The Moscow Fog		Tangerine/t-Rex			53	tan-mfog.zip
11. Trance-X Vibes		XPEh/LooKER house		53dq	txv.zip
12. Transexplorer		Xtreme				52	t_explor.zip
13. Beyond the Calmness		Dying Breed			47	beyond.zip
14. valley of the blindbirds	Rogers/QMG			38	vobbcomp.zip
15. Stupid Smiler's Club	MAG				37	smile.zip
15. POST!			VanaPoo/Virtual illusions	37	post!.zip
16. Motion			Thunder God/Team COLOBOC	35	to65.zip
17. REVOLUTION			wave/LOOKER hOUSE		34dq	revolut.zip
18. Fathers			Rony kiloMeters/DDT		33	fathers.zip
19. HYMN			Morpheus			32	mor-hymn.zip
20. must			Andrey Malyev/PI software	28	must.zip
21. Reggae			Grom/Fire Bird			27	island.zip
22. fake love			IMP/RUSH			25	fakelove.zip
23. Music is our emotions	Master_Koff/SoftMotion group	19	emotions.zip
24. Holo Drance #2		Mad Wild/Digital Cascade	18	rave#5.zip
25. MadNess			Gray Engine/Future Hackers	14	hicky.zip
25. The last illusion		Voider				14	vo-ill.zip
26. Life Underground		Hi-jack/NewGEN			10	life_und.zip
27. NBA				EVA/RTT				9	nba.zip
28. Noice Motion		Popirin Denis/CrossRoad		8	noicem.zip
29. Digital Dreams		Stas				7	digitald.zip

Graphics compo

 1. Lions of Darkness		Royal Ghost/DDT		73	ddt-lion.zip
 2. Machine			Gregor Barbarian	68	machine.zip
 3. Project			?			60	project.zip
 4. Ganjaman			?			54	ganjaman.zip
 5. Water World			Royal Ghost/DDT		50	ddt-ww.zip
 6. Modify1			Voider			49	voider.zip
 7. Peredoz			Boss/Eternal		47	eternal.zip
 8. Taladas			Cat/ACiD		45	acid.zip
 9. Attack			Terror/DR/RPSG		38	dr_rpsg.zip
10. Dragon			Terror/DR/RPSG		30	dr_rpsg.zip
11. Sarcastic Toaster		Cat/ACiD		28	acid.zip
11. Fenka2			Voider			28	voider.zip
12. The Alien WorkShop		Cat/ACiD		25	acid.zip
13. Zmey			Voider			19	voider.zip
14. Hardcore			Boss/Eternal		17	eternal.zip
14. Untitled			Rogers/QMG		17	untitled.zip
15. Coupling			Dmitry Skavish/IV	16	sd.zip
15. Godsmeal			Dmitry Skavish/IV	16	sd.zip
16. Male1			Cat/ACiD		14	acid.zip
16. My Dream			Terror/DR/RPSG		14	dr_rpsg.zip
17. Face			Boss/Eternal		13	eternal.zip
18. Freedom of Speech		Terror/DR/RPSG		12	rd_rpsg.zip
19. Starship			Boss/Eternal		10	eternal.zip
20. Myth			Boss/Eternal		5	eternal.zip
20. Cock			Dmitry Skavish/IV	5	sd.zip
20. Scrubs2			Voider			5	voider.zip
21. Enigma			Dmitry Skavish/IV	4	sd.zip

Amiga 64k intro compo

 1. AGA inside			XL-Design		-dq

ZX Demo compo

 1. Illusion			X-Trade Group		257
 2. Vibrations			RUSH			241
 3. Eye Ache			CodeBusters		234
 4. 7th Reality			DR/RPSG			185
 5. Influence			Seamans B.U.H.G.	150
 6. Action			Vav			137
 7. Life Sux			Galaxy Inc		51
 8. Ice Cream			World Eyes		31
 9. Daf				Digital Arts		5
 9. Made In Kazan		Excess Group		5
10. Miracle			WarLocks Group		3
11. Russian Prestige		Black Shark/RPSG	2

ZX Spectrum Music

 1. Likemya       		Joe/DR/RPSG			108
 2. DNK-1       		DNK/VirtGroup     		99
 3. KSA INS       		KSA       			96
 4. KPYTEXHO       		Evolver/RUSH      		73
 5. Stop       			MIC/MPS        			69
 6. 19 MGN.W       		KSA        			62
 7. Malikov       		Slash/Slash ADG/RPSG   		60
 8. DNK-2       		DNK/VirtGroup       		57
 9. E'96			Joe/DR/RPSG           		53
10. Larel_E       		A.Mihaylov/Scorpion & K H.G.	49
10. ChessBoard       		Magic Soft     			49
11. Intro1       		Alien/VirtGroup       		45
11. Myst       			Sauron/DR/RPSG       		45
12. Love'96                  	Slash/Slash ADG/RPSG   		37
13. Nothing Forever      	Magic Soft        		31
14. Destiny      		Comp-MS/Scorpion Club 		28
15. Forever       		Comp-MS/Scorpion Club		26
16. Enlight       		Dexter/Galaxy Inc       	25
16. CR2        			A.Mihaylov/Scorpion & K H.G.	25
16. Steam-2       		Bobov I.   			25
17. :-/        			MIC/MPS        			24
18. Cube       			World Eyes        		22
18. Never       		Alien/VirtGroup       		22
19. TN2        			Evolver/RUSH       		10
20. Grave 3.0       		Pahomov Sergey        		8
21. Improvization one      	Pahomov Sergey        		5
21. Rave4a       		BOBOV I         		5

ZX Spectrum Graphics

 1. Tiger       		Lemming/Scorpion Club     	109
 2. Chaos+       		Magic Soft       		106
 3. Chaos       		Viator/RUSH       		72
 4. Dark God       		Kamikaze/RUSH       		66
 5. Kazansk       		Observer/VirtGroup       	65
 6. Knight       		Lemming/Scorpion Club      	57
 7. Slavik1       		Barkov        			56
 8. St.Peter       		Observer/VirtGroup       	54
 9. Fil4       			Fil Gfx/Scorpion Club      	51
10. Before the storm      	Magic Soft        		49
11. Rush       			Viator/RUSH       		45
12. Fil2       			Fil Gfx/Scorpion Club      	39
13. Shaoinlg       		M.O.C./VirtGroup       		38
13. Go        			Bobov Ivan        		38
14. Life Shit       		Tihonov A.        		26
15. Znachok       		M.O.C./VirtGroup       		25
15. Steel       		Lemming/Scorpion Club      	25
16. Fil3       			Fil Gfx/Scorpion Club      	22
16. Hard Rock       		Tihonov A.        		22
17. Fil1       			Fil Gfx/Scorpion Club      	21
17. Fly_C       		Bobov Ivan        		21
18. Castles3       		Observer/VirtGroup       	18
18. FirePlay       		Lemming/Scorpion Club      	18
19. Term       			Alien/VirtGroup       		13
20. Birga       		Alien/VirtGroup       		12
20. Fractals      		Cobra/Enigma       		12
21. I.Maiden      		Tihonov A.        		11
22. Castle       		Lion/Excess Group        	9
22. Virtual World      		Magic Soft         		9
23. Magland       		M.O.C./VirtGroup        	5
23. GGG        			Sobolev E.V./Scorpion & K H.G.	5
23. Eclipse       		Bobov Ivan			5
24. S_hunt       		Bobov Ivan			4
25. Paralich       		Tihonov A.  		      	3

dq - disqualified



10. DEMOS, INTROS, DEMO_REL, DEMO_SRC, DISKMAGS файлэхи.

DEMOS   	- Demos  (~100k..~4MB)
INTROS   	- Intros (0..~100k)
DISKMAGS  	- Disk magazines (diskmags, party reports)
DEMO_SRC  	- Demo/intro/various effects sources, documentation
DEMO_REL  	- Misc demo related stuff (trackers, utils, etc..)
Moderator   - Peter Sobolev, 2:5030/84, coderipper@auro.spb.su
CoModerator - Mike Malakhov, 2:5030/280 (down)

Все файлэхи пpемодеpиpуемые. Желающие поместить туда что-либо пишут мне нетмейл

Также все обсуждения касающиеся данных файлэх пpиветствуются в DEMO.DESIGN.WANTED

В 5030 я pаздаю эти файлэхи на /16 /103 /248 /544

Возможно, вам поможет следующий список адpесов где были замечены вышеуказанные файлэхи:

463/118              50/330                  5001/7
463/159  471/23.17   50/777.32  5000/33      5005/37.8
463/340  471/23.226  50/777.44  5000/47      5005/38
463/530  471/23.65                           5005/39
464/51   471/23.82              5000/83.12   5005/41.3
465/70                                       5007/3
469/79                                       5007/3.30
                                             5007/5.1
                                             5011/22.10
                                             5011/36.103

5020/1000    5021/1.5     5030/103      5033/5
5020/158.24  5021/12      5030/135.2    5037/4.5
5020/170.9   5021/2.28    5030/142.21   5049/30
5020/170.9   5021/6.24    5030/16       5054/12.27
5020/201     5023/10      5030/191      5054/25
5020/235.40  5023/9.11    5030/195.9    5054/26
5020/238.14  5025/18      5030/240      5056/112
5020/249.8   5025/2.65    5030/248.33   5056/1.39
5020/265     5025/2.65    5030/249      5057/14
5020/265.9   5025/23.49   5030/249      5057/14
5020/269                  5030/275      5057/18.19
5020/269                  5030/316.30   5057/19
5020/299                  5030/316.31   5057/2.3
5020/312.9                5030/327      5057/25.4
5020/348.3                5030/329.5    5057/4.23
5020/384                  5030/331      5074/8.5
5020/438.17               5030/344.16   5074/9
5020/466                  5030/346.13   5100/56.14
5020/476                  5030/370
5020/477.39               5030/444.2
5020/477.39               5030/444.55
5020/480.10               5030/444.7
5020/480.14               5030/489
5020/487                  5030/498
5020/491.91               5030/499.29
5020/506                  5030/514
5020/551                  5030/528
5020/636                  5030/544
5020/636.11               5030/558
5020/637                  5030/558.10
5020/640                  5030/560
5020/657.100              5030/248
5020/662
5020/706
5020/709
5020/717
5020/724
5020/739.33
5020/741.8
5020/756.10
5020/775
5020/779
5020/787
5020/789
5020/795


11.Благодаpности

Спасибо всем, кто помог советом/замечанием/куском текста или кода. Пусть и невольно ;)

Oleg Homenko (461/318.50)
Vladimir Medeiko (5030/84.219)
Lenik Terenin (5061/1)
Alexey Kolpikov (5061/7)
Mike Malakhov (5030/280)
Paul Nosikoff
Peter Sobolev (5030/84)
Alex Starkov (5030/248)
Andrej Tepelin
Leon de Boer
Cyril Antonov (5030/6.200)
Andrew Eigus
Andrew Zabolotny (5030/84.5)
Maxime Zakharov
Zoombapup
LazyHAM
Alexander Amelkin
Serguey Zefiroff (5020/509.601)
Dmitry Skavish (5030/175)
Yury Oreshkin (2:4641/41.77)
Alex Victorov (2:5025/9.43)
Bretton Wade
Mike Shirobokov, (2:5057/14)
Lout Roman, 2:463/586.20