- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Графика DirectX в Delphi - Михаил Краснов
Шрифт:
Интервал:
Закладка:
i : Integer;
begin
for i := 0 to Size do begin
if Particle [i] .Energy > 0 then begin
Particle [i] .X := Particle [i] .X + Particle [i]. SpeedX;
// Частицы отскакивают от границ экрана
if Particle [i] .X >= ScreenWidth - 1 then begin
Particle [i ] .SpeedX :="-0.5 * Particle [i]. SpeedX;
Particle [i] .X := ScreenWidth - 1;
end;
if Particle [i] .X < 0 then begin
Particle [i] .SpeedX := -0.5 * Particle [i]. SpeedX;
Particle [i] .X := 0;
end;
Particle [i].Y := Particle [i] .Y + Particle [i] . SpeedY;
if Particle [i] .Y >= ScreenHeight - 1 then begin
Particle [i] .SpeedY := -0.3 * Particle [i] . SpeedY;
Particle[i] .Y := ScreenHeight - 1;
end;
if Particle [i] .Y < 0 then begin
Particle [i] .SpeedY := -Particle [i] . SpeedY;
Particle[i].Y := 0;
end;
Particle[i].Energy := Particle[i].Energy - 1;
Particle[i].SpeedY := Particle[i].SpeedY + 0.2;
end;
end;
end;
Самый главный для нас метод - воспроизведение частиц системы:
function TParticleSystem.Render : HRESULT;
var
i : Integer;
desc : TDDSURFACEDESC2;
hRet : HRESULT;
begin
ZeroMemory (@desc, SizeOf(desc));
desc.dwSize := SizeOf(desc);
hRet := frmDD.FDDSBack.Lock (nil, desc, DDLOCKJSAIT, 0);
if Failed (hRet) then begin Result := hRet;
Exit;
end;
// Очистка экрана
ZeroMemory (desc.IpSurface,
desc.lPitch * ScreenHeight * (ScreenBitDepth div 8));
// Заполняем пикселы в соответствии с состоянием системы частиц
for i := 0 to Size do
if (Particle[i].Energy > 0) then
PWord (Integer(desc.IpSurface) +
trunc (Particle[i].Y) * desc.lPitch +
trunc (Particle[i].X) * (ScreenBitDepth div 8))^ :=
Particle[i].B or (Particle[i].G shl 5) or (Particle[i].R shl 11);
Result := frmDD.FDDSBack.Unlock(nil) ;
end;
При каждой перерисовке экрана отображается текущее состояние системы:
function TfrmDD.UpdateFraine : HRESULT;
var
hRet : HRESULT;
begin
Result := DD_FALSE;
PS.Calculate; // Пересчитываем положения частиц
// Воспроизведение состояния системы
hRet := PS.Render;
if Failed (hRet) then begin
Result := hRet;
Exit;
end;
Time := Time + 1; // Простейший эмулятор таймера
if Time > 15 then begin // Прошел срок существования системы
PS.Init(DEFAULT_SIZE, DEFAULT_POWER); // Вспышка в новом месте
Time := 0;
end;
Result := DD_OK;
end;
Полупрозрачность
Такой прием часто используется в играх. Автоматизации полупрозрачности DirectDraw не предоставляет, все необходимо делать самому разработчику, попикселно накладывая данные источника и приемника.
В общем случае формула вычисления значения цветовых компонентов выглядит так:
Result = Alpha * srcColor + (1 - Alpha) * destColor
Здесь Alpha - коэффициент прозрачности, принимающий вещественное значение в пределах от нуля до единицы; srcColor - цвет источника; destColor - цвет приемника.
Если Alpha равно нулю, то получаем цвет приемника; если Alpha имеет единичное значение, источник совершенно непрозрачен. Если мы имеем дело с образом, двигающимся по поверхности, то под источником подразумеваем образ, а фон считаем приемником.
Формулу можно оптимизировать. Начнем с того, что избавимся от присутствия двух операций умножения. Перестроим уравнение так, чтобы присутствовала лишь одна из них:
Result = Alpha * srcColor + destColor - Alpha * destColor
ИЛИ
Result = Alpha * (srcColor - destColor) + destColor
Коэффициент прозрачности имеет смысл представлять целым, чтобы все вычисления производить только с целыми числами. Считая Alpha целым в интервале 0 - 256, окончательную формулу расчета составляющей запишем так:
Result = (Alpha * (srcColor - destColor)) / 256 + destColor
Все предваряющие слова сказаны, можем перейти к иллюстрации - проекту каталога Ех18, при работе которого по знакомому фону перемещается полупрозрачный образ насекомого (рис. 3.8).
Массив Pict содержит битовую карту растра:
const
imageWidth = 84;
imageHeight = 80;
Alpha = 127; var
Pict : Array [0..imageWidth - 1, 0..imageHeight - 1] of Word;
ColorKey : Word; // Вспомогательный цветовой ключ
Поверхность образа не выводится на экран, а служит только для заполнения массива pict:
function TfrmDD.Prepare : HRESULT;
var
desc : TDDSURFACEDESC2;
i, j : Integer;
hRet : HRESULT; begin
Result := DD_FALSE;
ZeroMemory (@desc, SizeOf(desc) );
desc.dwSize := SizeOf(desc);
hRet := FDDSImage.Lock (nil, desc, DDLOGK_WAIT, 0);
if Failed (hRet) then begin Result := hRet;
Exit;
end;
// Заполнение массива Pict
for i := 0 to imageWidth - 1 do
for j := 0 to imageHeight - 1 do
Pict [i, j] := PWORD (Integer (desc.IpSurface) + j * desc.lPitch + i * (ScreenBitDepth div 8))^;
ColorKey := Pict [0,0]; // Определяемся с цветовым ключом
Result := FDDSImage.Unlock (nil);
end;
Для простоты в качестве цветового ключа возьмем значение самого первого пиксела образа, считая, что цвет его совпадает с цветом фона. Для ускорения работы примера воспользуемся приемом с частичным обновлением экрана:
function TfrmDD.UpdateFrame : HRESULT;
var
X, Y : Integer; wrkRect : TRECT; hRet : HRESULT;
begin
ThisTickCount := GetTickCount;
if ThisTickCount - LastTickCount > 60 then begin X := 288 + trunc (cos(Angle) * 150);
Y := 208 + trunc (sin(Angle) * 150);
// Старая позиция образа
SetRect (wrkRect, X, Y, X + imageWidth, Y + imageHeight);
Angle := Angle + 0.05;
if Angle > 2 * Pi then Angle := Angle -2 * Pi;
// Вывод полупрозрачного образа в задний буфер
hRet := Blend (288 + trunc (cos(Angle) * 150),
208 + trunc (sin(Angle) * 150)); if Failed (hRet) then begin Result := hRet;
Exit;
end;
// Переключаем страницы hRet := FlipPages;
if Failed (hRet) then begin Result := hRet;
Exit;
end;
// Стираем образ в заднем буфере
hRet := FDDSBack.Blt (@wrkrect, FDDSBackGround, SwrkRect,
DDBLT_WAIT, nil); if Failed (hRet) then begin
Result := hRet;
Exit;
end;
LastTickCount := GetTickCount;
end;
Result := DD_OK;
end;
Итак, осталось рассмотреть собственно функцию вывода полупрозрачного образа:
function TfrmDD.Blend (const X, Y : Integer) : HRESULT;
var
desc : TDDSURFACEDESC2; i, j : Integer;
wrkPointer : PWORD;
sTemp, dTemp : WORD;
sb, db, sg, dg, sr, dr : Byte;
blue, green, red : Byte;
hRet : HRESULT;
begin
ZeroMemory (@desc, SizeOf (desc) ) ; desc.dwSize := SizeOf(desc);
hRet := FDDSBack.Lock (nil, desc, DDLOCK_WAIT, 0) ;
if Failed (hRet) then begin Result := hRet;
Exit;
end;
for i := 0 to imageWidth - 1 do
for j := 0 to imageHeight - 1 do
// Только для точек с цветом, отличным от цвета фона if Pict [i, j] <> ColorKey then begin
wrkPointer := PWORD (Integer(desc.IpSurface) +
(Y + j) * desc.lPitch + (X + i) * (ScreenBitDepth div 8));
sTemp := Pict [i, j]; // Пиксел источника, точка образа
dTemp := wrkPointer^; // Приемник, фоновая картинка
sb = sTemp and $lf; // Синий цвет источника
db = dTemp and $lf; // Синий цвет приемника
sg = (sTemp shr 5) and $3f; // Зеленый цвет источника
dg = (dTemp shr 5) and $3f; // Зеленый цвет приемника
sr = (sTemp shr 11) and $lf; // Красный цвет источника
dr = (dTemp shr 11) and $lf; // Красный цвет приемника
blue := (ALPHA * (sb - db) shr 8) -t- db; // Результат, синий
green := (ALPHA * (sg - dg) shr 8) + dg; // Результат, зеленый
red := (ALPHA * (sr - dr) shr 8) + dr; // Результат, красный
// Сложение цветовых компонентов в пикселе приемника
wrkPointer^ := blue or (green shl 5) or (red shl 11);
end;
Result := FDDSBack.Unlock (nil);
end;
Вы должны обратить внимание, что фон в примере заполняется растянутым растровым изображением. Мы уже обсуждали проблему, связанную с использованием метода DDReLoad в таких случаях. Чтобы при распахивании минимизированного окна картинка не превращалась в мозаику, перезагрузим растр:
function TfrmDD.RestoreAll : HRESULT;
var
hRet : HRESULT; begin
hRet := FDDSPrimary._Restore;
if Succeeded (hRet) then begin
FDDSBackGround := nil; // Удаление поверхности
FDDSBackGround := DDLoadBitmap(FDD, groundBmp, ScreenWidth,
ScreenHeight); // Заново создаем поверхность фона
if FDDSBackGround = nil then ErrorOut(DD_FALSE, 'DDLoadBitmap');
if FDDSBackGround = nil then ErrorOut(DD_FALSE, 'DDLoadBitmap');
hRet := FDDSPrimary.Blt (nil, FDDSBackGround, nil, DDBLT_WAIT, nil);
if Failed (hRet) then begin Result := hRet;
Exit;
end;
Result := FDDSBack.Bit (nil, FDDSBackGround, nil, DDBLT_WAIT, nil);
end else Result := hRet;
end;
Картинка загружается заново, и в случае неудачи загрузки программа заканчивает работу.
Обратите внимание, что в примере растр для заполнения фона берется 24-битным, а второй, накладываемый, растр имеет разрядность 8 бит, т. е. используется 256-цветный рисунок. В таких случаях не требуется загружать палитру из этого рисунка, поскольку все цвета при переносе на 24-битную поверхность отображаются корректно. Формат пиксела первичной поверхности задает формат пиксела и для всех остальных поверхностей. Не должна возникать ситуация, когда на 8-битную первичную поверхность помещается 16-битный образ. Также палитра, устанавливаемая для первичной поверхности, задается для всех остальных поверхностей. В таких примерах мы не загружали и не устанавливали палитры ни для одной поверхности, кроме первичной. Из-за этого в примерах с летающим драконом его цвета немного искажались, для отображения использовалась палитра фоновой поверхности.
Теоретически, DirectDraw сам проследит, чтобы не возникло разнобоя в установках поверхностей, но я думаю, что если вы будете явно устанавливать одинаковый формат для всех поверхностей, то только повысите корректность работы программы, особенно в случае оконных приложений.
Использование полупрозрачности позволит придать нашим проектам потрясающую эффектность, такую, как в следующем, очень интересном, примере - проекте каталога Ех19. Идея такова: после запуска приложения содержимое рабочего стола копируется на первичную поверхность, а по ходу работы появляется полупрозрачное изображение. У пользователя создается ощущение того, что приложение осуществляет вывод прямо на рабочий стол. Но мы этого не делаем, иначе окно приложения нарушит иллюзию.
Для простоты накладываем одно ограничение: считаем разрешение экрана 16-битным, размеры рабочего стола - 640x480 пикселов. Обратите внимание на это, при других установках рабочего стола пример работает не так эффектно.

