Win32 绘图基础 -- 绘制直线、边框、贝塞尔曲线、填充、裁剪
2012-11-10 00:37
615 查看
注:以下内容为学习笔记,多数是从书本、资料中得来,只为加深印象,及日后参考。然而本人表达能力较差,写的不好。因非翻译、非转载,只好选原创,但多数乃摘抄,实为惭愧。但若能帮助一二访客,幸甚!
设备环境中包含许多GDI函数如何工作的属性。
获取设备环境句柄:
1)在处理WM_PAINT消息时使用BeginPaint函数和EndPaint函数:
2)在处理非WM_PAINT消息时由Windows程序获取:
3)获得用于整个窗口的,而不仅仅是窗口客户区的设备环境句柄:
4)更通用的获取设备环境句柄的函数:
5)处理位图时,有时可能会用到一个”内存设备环境“:
可以把一个位图选入内存设备环境,并且调用GDI函数绘制这个位图
6)图元文件是以二进制形式编码的GDI函数调用的集合。它可以通过获取一个图元文件的设备环境来创建:
常用函数:
GetSystemMetrics、GetDeviceCaps.
1)色彩平面的数目:
2)每个像素的颜色位数:
2)直线
数组的点连成线:
用Polyline实现绘制正玄曲线:
绘图示例:
在Windows中有很多”空闲时间“,在这期间所有的消息队列都是空的,Windows就在等待键盘或者鼠标的输入。那么能否在空闲期间从某种程度上获取控制,而一旦有消息加载到程序的消息队列,就释放控制呢?这就是PeekMessage的”用武之地“。
PeekMessage的意思,它是”偷看“而不是”获得“。它允许一个程序检查程序队列中的下一个消息,而不是真实地获得并删除它看到的消息。
GetMessage并不把控制权交还给程序,除非它从程序的消息队列中获得了消息。但PeekMessage却总是立即返回,不管消息是否出现。
随机矩形代码:
9.矩形与区域的裁剪
InvalidRect函数使显示的矩形区域无效,并产生一个WM_PAINT消息。可以用来擦除客户区的内容,并产生一个WM_PAINT消息。
若处理区域而不是矩形可用:
InvalidateRgn(hwnd, hRgn, bErase);
ValidateRgn(hwnd, hRgn);
CLOVER程序:
由四个椭圆形成一个区域,然后把这个区域选入设备环境,接着从窗口的客户区中心发散绘制一系列直线。这些直线仅出现裁剪区内。
1.GDI
GDI 的一个主要目的就是支持与设备无关的图形。GDI提供了一种特殊的机制来彻底隔离应用程序和不同输出设备的特性,这样就可以支持与设备无关的图形。2.设备环境
如果希望在图形输出设备上绘图,必须首先获取设备环境(即DC)的句柄。当Windows把这个句柄交给你的程序,Windows同时也就给予了你使用这个设备的权限。接着,在GDI函数中将这个句柄作为一个参数,告诉Windows在哪个设备上进行绘图。设备环境中包含许多GDI函数如何工作的属性。
获取设备环境句柄:
1)在处理WM_PAINT消息时使用BeginPaint函数和EndPaint函数:
HDC hdc; hdc = BeginPaint(hwnd, &ps); // ... EndPaint(hwnd, &ps);
2)在处理非WM_PAINT消息时由Windows程序获取:
HDC hdc; hdc = GetDC(hwnd); //.... ReleaseDC(hwnd, hdc);
3)获得用于整个窗口的,而不仅仅是窗口客户区的设备环境句柄:
hdc = GetWindowDC(hwnd); // ... ReleaseDC(hwnd, hdc);
4)更通用的获取设备环境句柄的函数:
hdc = CreateDC(pszDriver, pszDevice, pszOutput, pData); // ... DeleteDC(hdc);获取当前整个屏幕的设备环境句柄:
hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
5)处理位图时,有时可能会用到一个”内存设备环境“:
hdcMem = CreateCompatibleDC(hdc); // .. DeleteDC(hdcMem);
可以把一个位图选入内存设备环境,并且调用GDI函数绘制这个位图
6)图元文件是以二进制形式编码的GDI函数调用的集合。它可以通过获取一个图元文件的设备环境来创建:
hdcMeta = CreateMetaFile(pszFilename); // ... hmf = CloseMetaFile(hdcMeta);
3.设备的尺寸
”分辨率“:每度量单位(通常是英寸)中含有的像素数。常用函数:
GetSystemMetrics、GetDeviceCaps.
4.色彩ABC
获取视频适配器板卡上的内存的组织形式:1)色彩平面的数目:
iPlanes= GetDeviceCaps(hdc, PLANES);
2)每个像素的颜色位数:
iBitsPixel = GetDeviceCaps(hdc, BITSPIXEL);
5.点和线的绘制
1)点SetPixel(hdc, x, y, crColor); crColor = GetPixel(hdc, x, y);
2)直线
MoveToEx(hdc, xBeg, yBeg, NULL); LineTo(hdc, xEnd, yEnd);
数组的点连成线:
Polyline(hdc, apt, 5);
用Polyline实现绘制正玄曲线:
/*------------------------------------------------------------------- SINEW***E.cpp -- sine wave Using polyline --------------------------------------------------------------------*/ #include <windows.h> #include <math.h> #define NUM 1000 #define TWOPI (2*3.14159) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("SineWave"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("Sine Wave Using Polyline"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static int cxClient, cyClient; HDC hdc; int i; PAINTSTRUCT ps; POINT apt[NUM]; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); MoveToEx(hdc, 0, cyClient/2, NULL); LineTo(hdc, cxClient, cyClient/2); for (i = 0; i < NUM; i++) { apt[i].x = i*cxClient/NUM; apt[i].y = (int)(cyClient / 2 * (1-sin(TWOPI * i / NUM))); } Polyline(hdc, apt, NUM); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
6.几个绘图函数:
Rectangle(hdc, xLeft, yTop, xRight, yBottom); Ellipse(hdc, xLeft, yTop, xRight, yBottom); RoundRect(hdc, xLeft, yTop, xRight, yBottom, xCornerEllipse, yCornerEllipse); Arc(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd); Chord(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd); Pie(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
绘图示例:
/*------------------------------------------------------------------- lineDemo.cpp -- Line-Drawing Demonstration Program --------------------------------------------------------------------*/ #include <windows.h> #include <math.h> #define NUM 1000 #define TWOPI (2*3.14159) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("lineDemo"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("Line Demonstration"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static int cxClient, cyClient; HDC hdc; PAINTSTRUCT ps; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); Rectangle(hdc, cxClient/8, cyClient/8, 7*cxClient/8, 7*cyClient/8); MoveToEx(hdc, 0, 0, NULL); LineTo(hdc, cxClient, cyClient); MoveToEx(hdc, 0, cyClient, NULL); LineTo(hdc, cxClient, 0); Ellipse(hdc, cxClient/8, cyClient/8, 7*cxClient/8, 7*cyClient/8); RoundRect(hdc, cxClient/4, cyClient/4, 3*cxClient/4, 3*cyClient/4, cxClient/4, cyClient/4); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
7.贝塞尔样条曲线:
/*------------------------------------------------------------------- bezier.cpp -- Bezier Splines Demo --------------------------------------------------------------------*/ #include <windows.h> #include <math.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("Bezier"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("Bezier Splines Demo"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void DrawBezier(HDC hdc, POINT apt[]) { PolyBezier(hdc, apt, 4); MoveToEx(hdc, apt[0].x, apt[0].y, NULL); LineTo(hdc, apt[1].x, apt[1].y); MoveToEx(hdc, apt[2].x, apt[2].y, NULL); LineTo(hdc, apt[3].x, apt[3].y); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static POINT apt[4]; int cxClient, cyClient; HDC hdc; PAINTSTRUCT ps; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); apt[0].x = cxClient / 4; apt[0].y = cyClient / 2; apt[1].x = cxClient / 2; apt[1].y = cyClient / 4; apt[2].x = cxClient / 2; apt[2].y = 3 * cyClient / 4; apt[3].x = 3 * cxClient / 4; apt[3].y = cyClient / 2; return 0; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MOUSEMOVE: if (wParam & MK_LBUTTON || wParam & MK_RBUTTON) { hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(WHITE_PEN)); DrawBezier(hdc, apt); if (wParam & MK_LBUTTON) { apt[1].x = LOWORD(lParam); apt[1].y = HIWORD(lParam); } if (wParam & MK_RBUTTON) { apt[2].x = LOWORD(lParam); apt[2].y = HIWORD(lParam); } SelectObject(hdc, GetStockObject(BLACK_PEN)); DrawBezier(hdc, apt); ReleaseDC(hwnd, hdc); } case WM_PAINT: InvalidateRect(hwnd, NULL, TRUE); hdc = BeginPaint(hwnd, &ps); DrawBezier(hdc, apt); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
8.填充区域
PeekMessage在Windows中有很多”空闲时间“,在这期间所有的消息队列都是空的,Windows就在等待键盘或者鼠标的输入。那么能否在空闲期间从某种程度上获取控制,而一旦有消息加载到程序的消息队列,就释放控制呢?这就是PeekMessage的”用武之地“。
PeekMessage的意思,它是”偷看“而不是”获得“。它允许一个程序检查程序队列中的下一个消息,而不是真实地获得并删除它看到的消息。
GetMessage并不把控制权交还给程序,除非它从程序的消息队列中获得了消息。但PeekMessage却总是立即返回,不管消息是否出现。
随机矩形代码:
/*------------------------------------------------------------------- randRect.cpp -- Displays Random Rectangles --------------------------------------------------------------------*/ #include <windows.h> #include <stdlib.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void DrawRectangle(HWND); int cxClient, cyClient; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("RandRect"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("Rand Rectangle"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (TRUE) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else { Sleep(100); DrawRectangle(hwnd); } } return msg.wParam; } void DrawRectangle(HWND hwnd) { HBRUSH hBrush; HDC hdc; RECT rect; if (cxClient == 0 || cyClient == 0) return; SetRect(&rect, rand() % cxClient, rand() % cyClient, rand() % cxClient, rand() % cyClient); hBrush = CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256)); hdc = GetDC(hwnd); FillRect(hdc, &rect, hBrush); ReleaseDC(hwnd, hdc); DeleteObject(hBrush); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
9.矩形与区域的裁剪
InvalidRect函数使显示的矩形区域无效,并产生一个WM_PAINT消息。可以用来擦除客户区的内容,并产生一个WM_PAINT消息。
若处理区域而不是矩形可用:
InvalidateRgn(hwnd, hRgn, bErase);
ValidateRgn(hwnd, hRgn);
CLOVER程序:
由四个椭圆形成一个区域,然后把这个区域选入设备环境,接着从窗口的客户区中心发散绘制一系列直线。这些直线仅出现裁剪区内。
/*------------------------------------------------------------------- clover.cpp -- Clover Drawing Program Using Regions --------------------------------------------------------------------*/ #include <windows.h> #include <math.h> #define TWO_PI (2.0 * 3.14159) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void DrawRectangle(HWND); int cxClient, cyClient; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("clover"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("Draw a Clover"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HRGN hRgnClip; static int cxClient, cyClient; double fAngle, fRadius; HCURSOR hCursor; HDC hdc; HRGN hRgnTemp[6]; int i; PAINTSTRUCT ps; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); ShowCursor(TRUE); if (hRgnClip) DeleteObject(hRgnClip); hRgnTemp[0] = CreateEllipticRgn(0, cyClient/3, cxClient/2, 2*cyClient/3); hRgnTemp[1] = CreateEllipticRgn(cxClient/2, cyClient/3, cxClient, 2*cyClient/3); hRgnTemp[2] = CreateEllipticRgn(cxClient/3, 0, 2*cxClient/3, cyClient/2); hRgnTemp[3] = CreateEllipticRgn(cxClient/3, cyClient/2, 2*cxClient/3, cyClient); hRgnTemp[4] = CreateRectRgn(0, 0, 1, 1); hRgnTemp[5] = CreateRectRgn(0, 0, 1, 1); hRgnClip = CreateRectRgn(0, 0, 1, 1); CombineRgn(hRgnTemp[4], hRgnTemp[0], hRgnTemp[1], RGN_OR); CombineRgn(hRgnTemp[5], hRgnTemp[2], hRgnTemp[3], RGN_OR); CombineRgn(hRgnClip, hRgnTemp[4], hRgnTemp[5], RGN_XOR); for (i = 0; i < 6; i++) DeleteObject(hRgnTemp[i]); SetCursor(hCursor); ShowCursor(FALSE); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); SetViewportOrgEx(hdc, cxClient/2, cyClient/2, NULL); SelectClipRgn(hdc, hRgnClip); // hypot 计算直角三角形斜边的长 fRadius = _hypot(cxClient/2.0, cyClient/2.0); for (fAngle = 0.0; fAngle < TWO_PI; fAngle += TWO_PI/360) { MoveToEx(hdc, 0, 0, NULL); LineTo(hdc, int(fRadius * cos(fAngle) + 0.5), int(-fRadius * sin(fAngle) + 0.5)); } EndPaint(hwnd, &ps); return 0; case WM_DESTROY: DeleteObject(hRgnClip); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
相关文章推荐
- Win32 绘图基础 -- 绘制直线、边框、贝塞尔曲线、填充、裁剪
- Android 绘图基础:Path(绘制三角形、贝塞尔曲线、正余弦)
- 第五章 绘图基础 (GDI、设备环境、点线绘制、填充)
- 学习Canvas绘图与动画基础 绘制直线(二)
- HTML5绘图基础_10_绘制多个弧线_填充
- Java基础之在窗口中绘图——绘制直线和矩形(Sketcher 2 drawing lines and rectangles)
- HTML5绘图基础_06_既填充区域又绘制线条
- Android 绘图基础:Canvas画布——自定义View基础(绘制表盘、矩形、圆形、弧、渐变)
- MATLAB绘图基础02-双坐标轴绘制
- MfC基础--绘图基础--win32
- Qt中2D绘图问题总结(一)----------基本的绘制与填充
- iOS绘图CALayer、UIBezierPath运用(边框、填充、复制、渐变)
- Java基础之在窗口中绘图——绘制星星(StarApplet 1)
- HTML5绘图基础_07_绘制第二个图形
- Java基础之在窗口中绘图——填充星型(StarApplet 2 filled stars)
- Android学习教程之2D绘图基础及绘制太极图
- 绘图基础--使用画笔和画刷绘制网络
- DirectX 3D_基础之模型表示 顶点格式 三角形 索引 虚拟摄像机 投影窗口 绘制流水线 局部坐标系 观察坐标系 世界坐标系 背面消隐 光照 裁剪 投影 视口变换 光栅化
- win32 窗口 绘制红色填充矩形
- Win32 OpenGL编程(3) 基本图元(点,直线,多边形)的绘制