|
Рисование полупрозрачных полигонов (Win32 API)
#36938622
Ссылка:
Ссылка на сообщение:
Ссылка с названием темы:
Ссылка на профиль пользователя:
|
Участник
Откуда: Санкт-Петербург
Сообщения: 665
|
|
2 kaktambaev:
Если очень хочется рисовать полу-прозрачные многоугольники с помощью GDI, то можно так:
(обработки ошибок нет, чтобы понятнее)
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96.
#include <assert.h>
#include <limits.h> // для INT_MIN, INT_MAX
void PaintTranslucentPolygon(HDC hDC, const POINT pVerts[], int NumVerts, COLORREF FillColor, int Opacity)
{
const unsigned int TransparentColor = 0xFF00FF; // magenta (ядовито-розовый цвет)
assert(NumVerts >= 3 );
assert(FillColor != RGB( 255 , 0 , 255 )); // не magenta
assert(( 0 <= Opacity) && (Opacity <= 255 ));
// считаем границы многоугольника
int MinX = INT_MAX;
int MaxX = INT_MIN;
int MinY = INT_MAX;
int MaxY = INT_MIN;
for (int i = 0 ; i < NumVerts; i++)
{
int x = pVerts[i].x;
if (x < MinX) MinX = x;
if (x > MaxX) MaxX = x;
int y = pVerts[i].y;
if (y < MinY) MinY = y;
if (y > MaxY) MaxY = y;
}
// слегка раздвигаем границы (чтобы избежать нежелательного отсечения)
MinX--;
MaxX++;
MinY--;
MaxY++;
// создаём временный буфер для вне-экранного рисования
int BufWidth = MaxX - MinX + 1 ;
int BufHeight = MaxY - MinY + 1 ;
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = BufWidth;
bi.bmiHeader.biHeight = BufHeight;
bi.bmiHeader.biPlanes = 1 ;
bi.bmiHeader.biBitCount = 32 ;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = 0 ;
bi.bmiHeader.biXPelsPerMeter = 0 ;
bi.bmiHeader.biYPelsPerMeter = 0 ;
bi.bmiHeader.biClrUsed = 0 ;
bi.bmiHeader.biClrImportant = 0 ;
void* pBufPixels;
HBITMAP hBuf = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pBufPixels, NULL, 0 );
// заполняем буфер прозрачным цветом
int NumPixels = BufHeight * BufWidth;
unsigned int* pPix = static_cast<unsigned int*>(pBufPixels);
for (int i = 0 ; i < NumPixels; i++)
{
*pPix++ = TransparentColor;
}
// рисуем многоугольник в буфер
HDC hBufDC = CreateCompatibleDC(NULL);
SelectObject(hBufDC, hBuf);
SelectObject(hBufDC, GetStockObject(DC_BRUSH));
SetDCBrushColor(hBufDC, FillColor);
SelectObject(hBufDC, GetStockObject(NULL_PEN)); // контур не рисовать
SetWindowOrgEx(hBufDC, MinX, MinY, NULL);
Polygon(hBufDC, pVerts, NumVerts);
SetWindowOrgEx(hBufDC, 0 , 0 , NULL);
// приводим содержимое буфера к формату с premultiplied alpha
pPix = static_cast<unsigned int*>(pBufPixels);
for (int i = 0 ; i < NumPixels; i++)
{
unsigned int c = *pPix;
if (c == TransparentColor)
{
*pPix = 0 ;
}
else
{
c |= 0xFF000000; // сделать alpha = 255
*pPix = c;
}
pPix++;
}
// рисуем содержимое буфера в указанный DC, со смешиванием (blending) цветов
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0 ;
bf.SourceConstantAlpha = Opacity;
bf.AlphaFormat = AC_SRC_ALPHA;
AlphaBlend(hDC, MinX, MinY, BufWidth, BufHeight, hBufDC, 0 , 0 , BufWidth, BufHeight, bf);
// освобождаем временные GDI-объекты
DeleteDC(hBufDC);
DeleteObject(hBuf);
}
Пример использования:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56.
case WM_PAINT:
{
PAINTSTRUCT PaintStruct;
HDC hDC = BeginPaint(hwnd, &PaintStruct);
// рисуем шашечки
int CellSize = 8 ;
int MinRow = PaintStruct.rcPaint.top / CellSize;
int MaxRow = PaintStruct.rcPaint.bottom / CellSize;
int MinCol = PaintStruct.rcPaint.left / CellSize;
int MaxCol = PaintStruct.rcPaint.right / CellSize;
HBRUSH hGrayBrush = static_cast<HBRUSH>(GetStockObject(LTGRAY_BRUSH));
HBRUSH hWhiteBrush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
for (int Row = MinRow; Row <= MaxRow; Row++)
{
for (int Col = MinCol; Col <= MaxCol; Col++)
{
RECT Cell;
Cell.left = Col * CellSize;
Cell.right = (Col + 1 ) * CellSize;
Cell.top = Row * CellSize;
Cell.bottom = (Row + 1 ) * CellSize;
FillRect(hDC, &Cell, (Row & 0x1) == (Col & 0x1) ? hGrayBrush : hWhiteBrush);
}
}
// рисуем прямоугольники
for (int Rect = 1 ; Rect <= 10 ; Rect++)
{
double CenterX = Rect * 30 ;
double CenterY = 50 ;
double Width = 20 ;
double Height = 80 ;
double Rot = 20 ; // угол в градусах
double hw = 0 . 5 * Width;
double hh = 0 . 5 * Height;
const double Pi = 3 . 1415926535897932384626433832795 ;
double cr = cos((Pi / 180 ) * Rot);
double sr = sin((Pi / 180 ) * Rot);
POINT Verts[ 4 ];
Verts[ 0 ].x = (int)(CenterX + cr * hw - sr * hh);
Verts[ 0 ].y = (int)(CenterY + sr * hw + cr * hh);
Verts[ 1 ].x = (int)(CenterX - cr * hw - sr * hh);
Verts[ 1 ].y = (int)(CenterY - sr * hw + cr * hh);
Verts[ 2 ].x = (int)(CenterX - cr * hw + sr * hh);
Verts[ 2 ].y = (int)(CenterY - sr * hw - cr * hh);
Verts[ 3 ].x = (int)(CenterX + cr * hw + sr * hh);
Verts[ 3 ].y = (int)(CenterY + sr * hw - cr * hh);
int Opacity = Rect * 255 / 10 ;
PaintTranslucentPolygon(hDC, Verts, 4 , RGB( 0 , 255 , 0 ), Opacity);
}
EndPaint(hwnd, &PaintStruct);
break;
}
Результат -- см. приложенный screenshot (снял в Windows 2000).
Но, GDI -- очень старый API, родом из 80-ых. Так что если хочется много рисовать с градиентами, anti-aliasing-ом и альфа-смешиванием, то я бы взял что-нибудь поновее: Cairo ( пример использования ) или GDI+ (не использовал).
|
|
|