Программирование на Visual C++. Архив рассылки - Алекс Jenter
Шрифт:
Интервал:
Закладка:
• Загрузкой растрового изображения с указанием, пикселы какого цвета считать прозрачными;
• Подготовкой специальной маски прозрачности – черно-белого растра, в котором пикселы черного цвета означают прозрачность для соответствующих точек основного растра. При этом маска прозрачности должна иметь такие же размеры, что и основной растр.
Нужно понимать, что в обоих случаях список изображений будет содержать маску прозрачности, просто при первом способе она будет создана за вас. Какой способ избрать – дело вкусов каждого программиста. Я обычно нахожу в палитре какой-нибудь ненужный цвет и назначаю его прозрачным. В большинстве случаев не везет ярко-сиреневому цвету (RGB 255,0,255).
Создание списков прозрачных изображенийСоздать список изображения и загрузить в него растр с прозрачностью можно так:
CBitmap m_Bmp;
m_Bmp.LoadBitmap(IDB_BITMAP1);
CImageList imgList;
imgList.Create(cx, cy, ILC_COLOR24|ILC_MASK, 1, 0);
imgList.Add(&m_Bmp, RGB(255, 255, 255));
В приводимых примерах будет предполагаться, что растровые изображения находятся в ресурсах программы и имеют глубину цвета 24 бита (16 млн. цветов). При создании списка необходимо указать размеры загружаемого растра (cx, cy), его цветовой формат (ILC_COLOR24, 16 миллионов оттенков) и признак наличия маски (ILC_MASK). Последние два параметра Create() определяют число хранимых в списке изображений и величину приращения списка при нехватке места. Макрос RGB удобен для указания цвета в 24-битовом диапазоне, в данном случае – цвета прозрачности.
В принципе, загрузить картинку можно и одним вызовом, но этот метод не поддерживает полноцветные изображения (как в нашем примере):
CImageList imgList;
imgList.Create(IDB_BITMAP1, cx, 0, RGB(255,255,255));
По умолчанию, такой растр ограничен 16 цветами.
Рисование с помощью Image ListДля чего списки изображений действительно полезны, так это для облегчения работы по рисованию. Вы вспомните навскидку число и порядок параметров у BitBlt()? А ее неудобство из-за необходимости подготовить дополнительный контекст устройства в памяти? Все это способно смутить не только новичка, но и более опытного программиста.
Ситуация еще более усложняется, когда мы имеем дело с прозрачностью. Необходимо выводить картинку несколько раз с различными параметрами растровых операций (Raster operation, ROP). Каждый раз, когда мы собираемся вывести на экран небольшое изображение космического корабля, необходимо проделать уйму работы.
К счастью, программисты Microsoft уже сделали ее за нас. Можно нарисовать растр, содержащийся в списке изображений, просто вызвав функцию ImageList_Draw(). С использованием MFC этот вызов выглядит, например, так:
imgList.Draw(pDC, 0, m_drawPoint, ILD_TRANSPARENT);
Здесь pDC – указатель на контекст устройства (CDC), 0 – порядковый номер выводимого из списка изображения, m_drawPoint — координаты начала области вывода. Флаг ILD_TRANSPARENT указывает, что вывод нужно осуществлять с учетом маски прозрачности.
Для самых любознательных сообщу, что реализация эффекта прозрачности при этом достигается методом, который Рон Джери называет Black Source Method, т.е., "метод черного источника". Он позволяет выводить изображение с прозрачными участками за два вызова BitBlt() вместо трех, но требует предварительно заменить пикселы, являющиеся прозрачными, черным цветом. Поэтому, загружая растр в список изображений, вы меняете его.
В результате вызова получится примерно вот что.
Отметим, что такой метод работает по принципу "все или ничего": если цвет пиксела изображения отличается от прозрачного хоть на один бит, он считается непрозрачным, что и заметно на примере области тени. Разница может быть незаметной для человеческого глаза, но не для компьютера. Зачастую спрайты рисуют в графических редакторах, сглаживающих картинку. При выводе такого изображения образуется ореол из пикселов, близких по цвету к прозрачному цвету фона, но все же не прозрачных (эффект гало). Поэтому рекомендуется рисовать такие растры на фоне, близком по цвету к фону выводимого изображения.
Windows 98 и библиотека msimg32.dllWindows 98 принесла новый простой способ вывода прозрачных изображений. Входящая в ее состав библиотека msimg32.dll содержит новые функции для получения соблазнительных графических эффектов. Для ее использования нужно подключить к проекту при сборке файл msimg32.lib.
Теперь растр с прозрачностью можно вывести за один прием с помощью функции TransparentBlt, указав прозрачный цвет в последнем параметре функции:
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap *temp = memDC.SelectObject(m_Bmp)
TransparentBlt(pDC->m_hDC, x, y, dstX, dstY, memDC.m_hDC, x1, y1, srcX, srcY, RGB(255,255,255));
memDC.SelectObject(temp);
"Ничего себе – за один прием!" скажете вы и …будете правы. Вновь появляется необходимость в совместимом контексте устройства, в котором нужно выбрать выводимый растр. Вновь – длинный (и не интуитивный) список параметров. Но зато появились возможности по управлению выводом. В данном примере x, y, x1, y1 – координаты начальной точки растра в приемнике и источнике соответственно. Параметры dstX и dstY – размеры области вывода, а srcX и srcY – ширина и высота прямоугольника, отображаемого из растра. Что если задать для них разные значения? Результат приведен здесь.
Как видим, эта функция содержит возможности по сжатию/растяжению растровых изображений. Только не переусердствуйте и не передайте в качестве размеров отрицательные значения – зеркального отображения TransparentBlt() создавать не умеет.
Добавим, что функция TransparentBlt() при выводе опирается на возможности DirectX данного устройства, что может дать прирост производительности по сравнению с традиционными методами.
СОВЕТ
Не забудьте после использования контекста устройства вновь выбрать в нем начальный растр (temp в нашем примере). В противном случае произойдет утечка графических ресурсов системы.
AlphaBlend(): "Полу" – не обязательно ½Все вышеописанные методы работают только с одной моделью прозрачности, называемой в компьютерной графике Chroma Key. Это означает, что прозрачным назначается определенный цвет. Другая, более развитая, модель называется Alpha Blending. При ее использовании для описания характеристик пикселов кроме цветовых компонент (R, G, B) применяется прозрачность (Alpha). Степень прозрачности определяется обратной величиной этого параметра.
Для поддержки этого режима Windows 98, а затем и Windows 2000 и Windows ME предоставляют функцию AlphaBlend():
BOOL AlphaBlend(HDC hdcDest, // handle to destination DC
int nXOriginDest, // x-coord of upper-left corner
int nYOriginDest, // y-coord of upper-left corner
int nWidthDest, // destination width
int nHeightDest, // destination height
HDC hdcSrc, // handle to source DC
int nXOriginSrc, // x-coord of upper-left corner
int nYOriginSrc, // y-coord of upper-left corner
int nWidthSrc, // source width
int nHeightSrc, // source height BLENDFUNCTION
blendFunction // alpha-blending function
);
Назначение ее параметров, в-общем, ясно из прототипа. Особый интерес представляет последний параметр – BLENDFUNCTION. Он представляет собой структуру (всего из четырех байт), определяющую режим вывода.
typedef struct _BLENDFUNCTION {
BYTE BlendOp;
BYTE BlendFlags;
BYTE SourceConstantAlpha;
BYTE AlphaFormat;
} BLENDFUNCTION, *PBLENDFUNCTION, *LPBLENDFUNCTION;
Что это такое? Дело в том, что AlphaBlend() может работать в двух разных режимах.
Простой режим (общая прозрачность)Первый (и наиболее простой в использовании) режим работы AlphaBlend() предполагает, что значение Alpha задано для всей картинки. В таком случае, оно применяется ко всем пикселам без исключения.
Формат BLENDFUNCTION в этом случае:
BLENDFUNCTION blend;
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.AlphaFormat = 0;
blend.SourceConstantAlpha = 180;
Для поля BlendOp в данный момент определено только одно допустимое значение — AC_SRC_OVER.
Поле BlendFlags должно содержать 0.
Плохо документированный параметр AlphaFormat определяет взаимодействие пикселов источника и приемника, о чем мы еще поговорим далее.
Параметр SourceConstantAlpha определяет степень непрозрачности. Задав для этого поля 0, вы не увидите свой растр вообще. Максимальное значение, умещающееся в тип BYTE, равно 255. При этом выводимый растр полностью перекроет область назначения. Но зачем вам, в таком случае, AlphaBlend()? И это значение используется, в-основном, для второго режима.
Режим с альфа-каналомОн требует некоторой дополнительной подготовки. В этом режиме растр, подготовленный для вывода, должен содержать информацию о степени прозрачности каждого пиксела. Это достигается, например, применением формата 32 бита на пиксел (по одному байту на каждый цветовой компонент и одному – на альфа-канал).