一般使用OpenGL在窗体绘制图形时,绘图背景很难透明,在Google找了一段代码,实现在透明窗体上绘制图形,具有镂空的效果,像桌面精灵一样。
分享代码:
001 | #define _WIN32_WINNT 0x0500 |
002 |
003 | #include <windows.h> |
004 | #include <windowsx.h> |
005 | #include <GL/gl.h> |
006 | #include <GL/glu.h> |
007 | #include <math.h> |
008 |
009 | const float PI=3.1415926154; |
010 | #pragma comment (lib, "opengl32.lib") |
011 | #pragma comment (lib, "glu32.lib") |
012 | //#pragma comment (lib, "glaux.lib") |
013 |
014 | #include <assert.h> |
015 | #include <tchar.h> |
016 |
017 | #ifdef assert |
018 | #define verify(expr) if(!expr) assert(0) |
019 | #else verify(expr) expr |
020 | #endif |
021 |
022 | const TCHAR szAppName[]=_T( "TransparentGL" ); |
023 | const TCHAR wcWndName[]=_T( "WS_EX_LAYERED OpenGL" ); |
024 |
025 | HDC hDC; |
026 | HGLRC m_hrc; |
027 | int w(240); |
028 | int h(240); |
029 |
030 | HDC pdcDIB; |
031 | HBITMAP hbmpDIB; |
032 | void *bmp_cnt(NULL); |
033 | int cxDIB(0); |
034 | int cyDIB(0); |
035 | //BITMAPINFOHEADER BIH; |
036 |
037 | BITMAPINFOHEADER BIH; |
038 |
039 | void polarCoorCircle( float radius, float circlePointX, float circlePointY) |
040 | { |
041 | float i,n=360.0; |
042 | float t = 2*PI/n,x,y; |
043 | glBegin(GL_LINE_LOOP); |
044 | for (i=0.0; i<n; i+=0.2) |
045 | { |
046 | x = radius*sinf(t*i); |
047 | y = radius*cosf(t*i); |
048 | glVertex2f(circlePointX+x,circlePointY+y); |
049 | } |
050 | glEnd(); |
051 | } |
052 |
053 | BOOL initSC() |
054 | { |
055 | glEnable(GL_ALPHA_TEST); |
056 | glEnable(GL_DEPTH_TEST); |
057 | glEnable(GL_COLOR_MATERIAL); |
058 |
059 | glEnable(GL_LIGHTING); |
060 | glEnable(GL_LIGHT0); |
061 |
062 | glEnable(GL_BLEND); |
063 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
064 | glClearColor(0, 0, 0, 1); |
065 |
066 | return 0; |
067 | } |
068 |
069 | void resizeSC( int width, int height) |
070 | { |
071 | glViewport(0,0,width,height); |
072 | glMatrixMode(GL_PROJECTION); |
073 | glLoadIdentity(); |
074 | //gluOrtho2D(0.0,500.0*aspect,0.0,500.0); |
075 | gluOrtho2D(0.0,width,0.0,height); |
076 | glMatrixMode(GL_MODELVIEW); |
077 | glLoadIdentity(); |
078 | } |
079 |
080 | BOOL renderSC() |
081 | { |
082 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); |
083 |
084 | glColor3f(0, 1, 1); |
085 | glLineWidth(10); |
086 | glBegin(GL_LINES); |
087 | glVertex2f(0,0); |
088 | glVertex2f(120,120); |
089 | glEnd(); |
090 | polarCoorCircle(120, 120, 120); |
091 | glFlush(); |
092 |
093 | return 0; |
094 | } |
095 |
096 | // DIB -> hDC |
097 | void draw( HDC pdcDest) |
098 | { |
099 | assert (pdcDIB); |
100 |
101 | verify(BitBlt(pdcDest, 0, 0, w, h, pdcDIB, 0, 0, SRCCOPY)); |
102 | } |
103 |
104 | void CreateDIB( int cx, int cy) |
105 | { |
106 | assert (cx > 0); |
107 | assert (cy > 0); |
108 |
109 | cxDIB = cx ; |
110 | cyDIB = cy ; |
111 |
112 | int iSize = sizeof (BITMAPINFOHEADER); |
113 | memset (&BIH, 0, iSize); |
114 |
115 | BIH.biSize = iSize; |
116 | BIH.biWidth = cx; |
117 | BIH.biHeight = cy; |
118 | BIH.biPlanes = 1; |
119 | BIH.biBitCount = 24; |
120 | BIH.biCompression = BI_RGB; |
121 | if (pdcDIB) |
122 | verify(DeleteDC(pdcDIB)); |
123 |
124 | pdcDIB = CreateCompatibleDC(NULL); |
125 | assert (pdcDIB); |
126 |
127 | if (hbmpDIB) |
128 | verify(DeleteObject(hbmpDIB)); |
129 |
130 | hbmpDIB = CreateDIBSection( |
131 | pdcDIB, |
132 | (BITMAPINFO*)&BIH, |
133 | DIB_RGB_COLORS, |
134 | &bmp_cnt, |
135 | NULL, |
136 | 0); |
137 |
138 | assert (hbmpDIB); |
139 | assert (bmp_cnt); |
140 |
141 | if (hbmpDIB) |
142 | SelectObject(pdcDIB, hbmpDIB); |
143 | } |
144 |
145 | BOOL CreateHGLRC() |
146 | { |
147 | DWORD dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP; |
148 |
149 | PIXELFORMATDESCRIPTOR pfd ; |
150 | memset (&pfd,0, sizeof (PIXELFORMATDESCRIPTOR)) ; |
151 | pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR); |
152 | pfd.nVersion = 1; |
153 | pfd.dwFlags = dwFlags ; |
154 | pfd.iPixelType = PFD_TYPE_RGBA ; |
155 | pfd.cColorBits = 24 ; |
156 | pfd.cDepthBits = 32 ; |
157 | pfd.iLayerType = PFD_MAIN_PLANE ; |
158 |
159 | int PixelFormat = ChoosePixelFormat(pdcDIB, &pfd); |
160 | if (PixelFormat == 0){ |
161 | assert (0); |
162 | return FALSE ; |
163 | } |
164 |
165 | BOOL bResult = SetPixelFormat(pdcDIB, PixelFormat, &pfd); |
166 | if (bResult==FALSE){ |
167 | assert (0); |
168 | return FALSE ; |
169 | } |
170 |
171 | m_hrc = wglCreateContext(pdcDIB); |
172 | if (!m_hrc){ |
173 | assert (0); |
174 | return FALSE; |
175 | } |
176 |
177 | return TRUE; |
178 | } |
179 |
180 | LRESULT CALLBACK WindowFunc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) |
181 | { |
182 | PAINTSTRUCT ps; |
183 |
184 | switch (msg) |
185 | { |
186 | case WM_ERASEBKGND: |
187 | return 0; |
188 | break ; |
189 |
190 | case WM_CREATE: |
191 | break ; |
192 |
193 | case WM_DESTROY: |
194 | if (m_hrc) |
195 | { |
196 | wglMakeCurrent(NULL, NULL); |
197 | wglDeleteContext(m_hrc) ; |
198 | } |
199 | PostQuitMessage(0) ; |
200 | break ; |
201 |
202 | case WM_PAINT: |
203 | hDC = BeginPaint(hWnd, &ps); |
204 | renderSC(); // OpenGL -> DIB |
205 | draw(hDC); // DIB -> hDC |
206 | EndPaint(hWnd, &ps); |
207 | break ; |
208 |
209 | case WM_SIZE: |
210 | w = LOWORD(lParam); h = HIWORD(lParam); |
211 | wglMakeCurrent(NULL, NULL); |
212 | wglDeleteContext(m_hrc); |
213 |
214 | CreateDIB(w, h); |
215 | CreateHGLRC(); |
216 | verify(wglMakeCurrent(pdcDIB, m_hrc)); |
217 |
218 | initSC(); |
219 | resizeSC(w, h); |
220 | renderSC(); |
221 | break ; |
222 |
223 | default : |
224 | return DefWindowProc(hWnd,msg,wParam,lParam); |
225 | } |
226 |
227 | return 0; |
228 | } |
229 |
230 | int WINAPI WinMain( HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR str, int nWinMode) |
231 | { |
232 | WNDCLASSEX wc; |
233 | memset (&wc, 0, sizeof (wc)); |
234 | wc.cbSize = sizeof (WNDCLASSEX); |
235 | wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); |
236 | wc.style = CS_HREDRAW | CS_VREDRAW; |
237 | wc.lpfnWndProc = (WNDPROC)WindowFunc; |
238 | wc.cbClsExtra = 0; |
239 | wc.cbWndExtra = 0; |
240 | wc.hInstance = hThisInst; |
241 | wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); |
242 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); |
243 | wc.hbrBackground = ( HBRUSH ) (COLOR_WINDOW); |
244 | wc.lpszClassName = szAppName; |
245 |
246 | if (!RegisterClassEx(&wc)) |
247 | { |
248 | MessageBox(NULL, _T( "RegisterClassEx - failed" ), _T( "Error" ), MB_OK | MB_ICONERROR); |
249 | return FALSE; |
250 | } |
251 |
252 | HWND hWnd = CreateWindowEx(WS_EX_LAYERED, szAppName, wcWndName, |
253 | WS_VISIBLE | WS_POPUP, 200, 150, w, h, |
254 | NULL, NULL, hThisInst, NULL); |
255 | if (!hWnd){ |
256 | MessageBox(NULL, _T( "CreateWindowEx - failed" ), _T( "Error" ), MB_OK | MB_ICONERROR); |
257 | return FALSE; |
258 | } |
259 |
260 | verify(SetLayeredWindowAttributes(hWnd, 0x0, 0, LWA_COLORKEY)); |
261 |
262 | MSG msg; |
263 | while (1) |
264 | { |
265 | while (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){ |
266 | if (GetMessage(&msg, NULL, 0, 0)) |
267 | { |
268 | TranslateMessage(&msg); |
269 | DispatchMessage(&msg); |
270 | } |
271 | else return 0; |
272 | } |
273 | } |
274 |
275 | return (FALSE); |
276 | } |
运行后的效果:
原理:OpenGL先绘制位图,然后将位图拷贝到设备中。
但是将代码移植到MFC自定义透明控件中,发现透明效果失效。如果有能实现OpenGL透明自定义控件的方法,请赐教。