Алгоритм работы прост: по экрану двигаются частицы, за каждой из которых тянется след. Срок жизни любой частицы ограничен, новые точки появляются в месте расположения курсора:
const
MaxParticles = 100000; // Верхнее ограничение по количеству точек type
TParticle = record // Тип для описания отдельной точки
X : Integer; // Координаты точки на экране
Y : Integer;
Angle : Single; // Угол направления движения
Speed : Integer; // Скорость движения
Decay : Single; // Время жизни
HalfLife : Single; // Срок существования
// Величина сдвига для угла, движение по спирали
AngleAdjustment : Single;
end;
var // Глобальные переменные модуля
ParticleCount : Integer = 10000; // Текущее количество точек
Particle : Array [0..MaxParticles] of TParticle; // Массив частиц
mouseX, mouseY : Integer; // Координаты курсора
// Растровый массив, хранит цвет для всех пикселов экрана
Pict : Array [0..ScreenWidth - 1, 0..ScreenHeight - 1] of Byte;
BlurFactor : Integer = 1; // Задает величину размытости следа
При начале работы приложения массив частиц заполняется первоначальными данными, и частицы располагаются хаотически по всему экрану:
for Index := 0 to MaxParticles do
with Particle [Index] do begin
Speed := 1 + round (random (3)) ;
Angle : = random * 2 * Pi;
X := random (ScreenWidth - 1) + 1;
Y := random (ScreenHeight - 1) + 1;
Decay := random;
HalfLife := random / 20;
AngleAdjustment := random / 20;
end;
При каждом обновлении экрана отслеживаются новые позиции частиц и усредняются цвета пикселов, подобно предыдущему примеру:
for Index := 0 to ParticleCount do
with Particle [Index] do begin
Decay := Decay - HalfLife; // Уменьшить время жизни
// Срок существования прошел, появляется новая точка
if Decay <= 0 then begin
Decay := 1;
X := mouseX; // В позиции курсора
Y := mouseY;
end;
Angle := Angle + AngleAdjustment; // Движение по спирали
If Angle >= 2 * Pi then Angle := 0; //От переполнения
X := X + round (cos(Angle) * Speed); // Новая позиция
Y := Y + round (sin(Angle) * Speed);
// Точка, ушедшая за границу экрана
if (X > ScreenWidth - 2) or (X < 2) then begin
X := mouseX; // Переместить в позицию курсора
Y : = mouseY;
Angle := random * 2 * Pi;
end
else if (Y > ScreenHeight - 2) or (Y < 2) then begin
X := mouseX;
Y := mouseY;
Angle := random '* 2 * Pi;
end;
// "Отображение" точки
Pict [X, Y] := Speed * 16 + 186;
end;
// Эффект размытости for Index := 1 to BlurFactor do for X := 2 to ScreenWidth - 2 do
for Y := 2 to (ScreenHeight - 2) do begin
// Усреднение значения девяти соседних элементов Accum := 0;
Accum := Accum + Pict [X, Y] +
Pict[X, Y + 1] + Pict[X, Y - 1] +
Pict[X + 1, Y] + Pict[X - 1, Y] +
Pict[X + 1, Y + 1] + Pict[X - 1, Y - 1] +
Pict[X + 1, Y - 1] + Pict[X - 1, Y + 1];
Accum := Accum div 9; // Усреднение значений
// соседних пикселов
Pict [X, Y] :=' Accum;
end;
Чтобы изображение не съеживалось с течением времени, как в предыдущем примере, закрашиваясь черным цветом, граничные точки экрана заполняются ненулевыми значениями:
for Index := 0 to ScreenWidth - 1 do begin
Pict[Index, 0] := 127;
Pict[Index, ScreenHeight - 1] := 127;
Pict[Index, 1] := 127;
Pict[Index, ScreenHeight - 2] := 127;
end;
for Index := 0 to ScreenHeight - 1 do begin
PictfO, Index] := 127;
Pict[ScreenWidth - 1, Index] := 127;
Pict[l, Index] := 127;
Pict[ScreenWidth - 2, Index] := 127;
end;
С помощью клавиш <���Ноте> и можно менять количество частиц, а с помощью клавиш и - управлять степенью усреднения пикселов.
Пример может работать при разных разрешениях и глубине цвета экрана. Обратите внимание, что при его очистке размер блока в таких случаях задается исходя из значения текущей глубины:
ZeroMemory (desc. IpSurface, desc.lPitch * ScreenHeight * (ScreenBitDepth div 8) ) ;
Также здесь нельзя использовать значение ширины экрана вместо lPitch, т. к. из-за выравнивания памяти это могут быть разные значения. Ширина поверхности "подгоняется" к границам параграфов, т. е. должна быть кратна 4-м байтам.
Массивы в видеопамять приходится переносить медленным способом - поэлементно. Одна ячейка массива занимает байт, при разрешении экрана в 16 разрядов на пиксел массив скопируется только в первую половину памяти поверхности. Если же вы в своем приложении не собираетесь менять разрешение, то вполне можете копировать массив целиком, одной командой CopyMemory.
Поскольку значения в массиве pict лежат в пределах диапазона типа Byte, то для 16-битного режима картинка получится не очень выразительной и отображается оттенками одного цвета.
Сохранение растровых изображений
Наверняка перед вами рано или поздно встанет задача сохранения получающихся картинок. Если вы попытаетесь их скопировать в буфер обмена для дальнейшей вставки в рисунок графического редактора, то обнаружите проблему с 256-цветными приложениями. Картинки будут искажаться, поскольку палитра таких изображений будет отличной от палитры рисунка.
Я приведу простейшее решение проблемы, основанное на использовании объекта класса TBitmap. В предыдущем примере обработчик формы нажатия клавиши приведите к следующему виду:
Читать дальше
Конец ознакомительного отрывка
Купить книгу