DirectX Графика в проектах Delphi

       

Лупа



В данном разделе мы рассмотрим два любопытных примера, посвященных организации лупы. Задача сама по себе занимательна, но вдобавок мы узнаем кое-что интересное и загадочное.
Запустите проект, располагающийся в каталоге Ех21. По экрану перемещается "лупа", кружок, в пределах которого выводится увеличенный участок фона (рис. 3.10).

Рис. 3.10. Имитация лупы

В качестве фона в примерах этого раздела я использую, с любезного разрешения автора, работы художника, имя которого присутствует в левом нижнем углу растрового изображения. Псевдоним автора - Beardo, а адрес ею страницы http://home5.swipnet.se/~w-57902/images/art/.
Изобразить увеличенный участок фона - задача не из трудных, мы хорошо усвоили метод Bit поверхности. Проблема состоит в том, чтобы вывести не прямоугольную, а именно круглую лупу. Посмотрим, как это сделано в данном примере.
Поверхность, связанная с лупой, называется FDDSZoom, для нее установлен цветовой ключ - черный цвет. Размер поверхности - 100x100 пикселов.
Все точки этой поверхности, находящиеся за пределами круга "лупы", окрашиваются черным:

function TfrmDD.Circle : HRESULT;
var
desc : TDDSURFACEDESC2;
i, j : Integer;
hRet : HRESULT; begin
ZeroMemory (@desc, SizeOf(desc));
desc.dwSize := SizeOf (desc);
hRet := FDDSZoom.Lock (nil, desc, DDLOCK_WAIT, 0); if Failed (hRet) then begin Result := hRet;
Exit;
end;
for i := 0 to 99 do // Цикл по всем точкам поверхности
for j := 0 to 99 do
// Выделяем точки, располагающиеся за пределами круга "лупы"
if sqr (i - 50} + sqr (j - 50) > 50 * 50 then // Заполняем черным
PWord (Integer(desc.IpSurface) + j * desc.lPitch + i * 2)^ := 0;
Result := FDDSZoom.Unlock (nil);
end;

При отображении цветовой ключ позволяет ограничить вывод растянутой поверхности именно кругом:

// Квадрат, задающий степень увеличения
SetRect (wrkRect, mouseX + 25, mouseY + 25, mouseX + 75, mouseY + 75);
// Растягиваем участок фона
FDDSZoom.Bit (nil, FDDSBackGround, SwrkRect, DDBLT_WAIT, nil);
Circle; // Заполняем черным часть квадрата
// Выводим с цветовым ключом
FDDSBack.BltFast (mouseX, mouseY, FDDSZoom, nil,
DDBLTFAST_WAIT or DDBLTFAST_SRCCOLORKEY);


Выглядит просто и эффектно, но в решении содержится проблема: оно подходит только для черного цвета. Если в качестве ключа использовать любой другой цвет, то на точки, заполненные цветом ключа "вручную", прозрачность распространяться не будет: прозрачными окажутся только участки этого же цвета, но окрашенные вызовом метода поверхности. Разрешить означенную проблему мне не удалось, поскольку плохо понятно, как DirectDraw удается различать такие участки.
Черный цвет для использования его в качестве ключа подходит для этого фона, но пример будет некрасиво работать с фоном, подобным рис. 3.11, где присутствует масса участков именно черного цвета.



Рис. 3.11. Работа усложненного примера на создание лупы

В проекте каталога Ех22 приведено другое решение задачи, менее элегантное, но работающее с любыми цветовыми ключами.
Здесь, помимо поверхности FDDSZoom, введена поверхность FDDSDouble. Для первой из них в качестве ключа взят чистый зеленый цвет, как отсутствующий на фоне. Вторая поверхность создается путем загрузки изображения-шаблона - зеленый квадрат с черным кругом посередине. Ключом для нее установлен черный цвет.
Теперь на поверхность лупы последовательно помещаем растянутый участок фона, затем ограничивающий шаблон:

SetRect (wrkRect, mouseX + 25, mouseY + 25, mouseX + 75, mouseY +- 75);
// Растягиваем участок фона
FDDSZoom.Blt (nil, FDDSBackGround, @wrkRect, DDBLT_WAIT, nil);
// Вместо черных участков шаблона останется увеличенный фрагмент
FDDSZoom.BltFast (О, О, FDDSDouble, nil,
DDBLTFASTJMAIT or DDBLTFAST^SRCCOLORKEY);
// Зеленая канва не воспроизведется FDDSBack.BltFast (mouseX, mouseY, FDDSZoom, nil,
DDBLTFAST_WAIT or DDBLTFAST_SRCCOLORKEY);

Позже мы вернемся к задаче с лупой и получим искаженное изображение в ее круге.


Содержание раздела