Программирование: тень от рисунка?
Я тут пытаюсь рисовать правильные тени. Что-то в таком роде:

Там текст кнопки отбрасывает тень. Область, куда отбрасывается тень, не является однотонной. Сам текст однотонный только в данном примере - можно отбрасывать тень от любого объекта.
Я напишу, как это сделано - возможно вам пригодится или вы посоветуете метод лучше? Может, в GDI+ есть что-то? Я сходу не нашел.
Пояснения, что есть что:
Итак. Пусть дан некий контекст (this). В нем уже что-то нарисовано, некий фоновый рисунок, куда будет отбрасываться тень (в примере - "стеклянная" кнопка). Поверх этого будет нарисована некая ХРЕНЬ, которая определяется параметром drawer. ХРЕНЬ должна отбросить тень на фон. Также дан некий прямоугольник r, в пределах которого все происходит.
Выше приведена - внешняя часть алгоритма. Конструктор создает новый контекст в памяти (CreateCompatibleDC), функция start выделяет память под прямоугольник (CreateCompatibleDC) и копирует туда фоновый рисунок из this (BitBlt). Далее функция DrawState рисует ХРЕНЬ со смещением на distance и делает ее однотонной (DSS_MONO). В результате в контексте mc получается тот же самый фон и поверх него - смещенный монохромный рисунок (черный). Потом этот рисунок в функции transparent смешивается с текушим рисунком при помощи AlphaBlend. Тень получается полупрозрачной, рисунок фона не теряется. Наконец, поверх всего этого ХРЕНЬ рисуется еще раз, без смещения и полупрозрачности.
Все вместе, если программировать с нуля, получается довольно длинно. А нет ли более дешевого способа?

Там текст кнопки отбрасывает тень. Область, куда отбрасывается тень, не является однотонной. Сам текст однотонный только в данном примере - можно отбрасывать тень от любого объекта.
Я напишу, как это сделано - возможно вам пригодится или вы посоветуете метод лучше? Может, в GDI+ есть что-то? Я сходу не нашел.
static BOOL CALLBACK DrawStateProc(
HDC hdc, // handle to device context
LPARAM lData, // image information
WPARAM wData, // more image information
int cx, // image width
int cy // image height
)
{
GContextDrawer *drawer= (GContextDrawer*)lData;
drawer->draw(GSimpleContext(hdc), GRect(0, 0, cx, cy));
return TRUE;
}
void GContext::drawShaded(const GRect &r, GContextDrawer &drawer, int distance)
{
if (distance != 0)
{
GMemoryContext mc(this);
mc.start(r, GMemoryContext::COPY_BITS|GMemoryContext::COPY_PARAMS);
HBRUSH brush= GBrush::createSolid(GColor::Black);
DrawState(mc.getHandle(), brush, DrawStateProc, (LPARAM)&drawer, NULL,
distance, distance, r.wid(), r.hig(), DST_COMPLEX|DSS_MONO);
DeleteObject(brush);
mc.transparent(50);
}
drawer.draw(*this, r);
}
Пояснения, что есть что:
- r - прямоугольник в пределах которого будет нарисовано нечто.
- GContext - простая обертка вокруг HDC (как CDC)
- GRect - прямоугольник (поля x1, y1, x2, y2)
- distance - расстояние "отброса" тени (по умолчанию 2)
- GContextDrawer - класс, описывающий некий абстрактный объект, который может нарисовать сам себя в указанном прямоугольнике указанного контекста: draw(GContext&, GRect&). В данном случае он просто пишет текст в этом прямоугольнике.
- GMemoryContext - контекст для рисования в памяти.
Итак. Пусть дан некий контекст (this). В нем уже что-то нарисовано, некий фоновый рисунок, куда будет отбрасываться тень (в примере - "стеклянная" кнопка). Поверх этого будет нарисована некая ХРЕНЬ, которая определяется параметром drawer. ХРЕНЬ должна отбросить тень на фон. Также дан некий прямоугольник r, в пределах которого все происходит.
Выше приведена - внешняя часть алгоритма. Конструктор создает новый контекст в памяти (CreateCompatibleDC), функция start выделяет память под прямоугольник (CreateCompatibleDC) и копирует туда фоновый рисунок из this (BitBlt). Далее функция DrawState рисует ХРЕНЬ со смещением на distance и делает ее однотонной (DSS_MONO). В результате в контексте mc получается тот же самый фон и поверх него - смещенный монохромный рисунок (черный). Потом этот рисунок в функции transparent смешивается с текушим рисунком при помощи AlphaBlend. Тень получается полупрозрачной, рисунок фона не теряется. Наконец, поверх всего этого ХРЕНЬ рисуется еще раз, без смещения и полупрозрачности.
Все вместе, если программировать с нуля, получается довольно длинно. А нет ли более дешевого способа?
no subject
no subject
no subject