- commit patch from Matthew Plough to request buffer with SWAP_COPY
[blender.git] / intern / ghost / intern / GHOST_WindowWin32.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 /**
33
34  * $Id$
35  * Copyright (C) 2001 NaN Technologies B.V.
36  * @author      Maarten Gribnau
37  * @date        May 10, 2001
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #include <string.h>
45 #include "GHOST_WindowWin32.h"
46 #include <GL/gl.h>
47
48 LPCSTR GHOST_WindowWin32::s_windowClassName = "GHOST_WindowClass";
49 const int GHOST_WindowWin32::s_maxTitleLength = 128;
50 HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL;
51
52 static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd);
53 static int EnumPixelFormats(HDC hdc);
54
55 /*
56  * Color and depth bit values are not to be trusted.
57  * For instance, on TNT2:
58  * When the screen color depth is set to 16 bit, we get 5 color bits
59  * and 16 depth bits.
60  * When the screen color depth is set to 32 bit, we get 8 color bits
61  * and 24 depth bits.
62  * Just to be safe, we request high waulity settings.
63  */
64 static PIXELFORMATDESCRIPTOR sPreferredFormat = {
65         sizeof(PIXELFORMATDESCRIPTOR),  /* size */
66         1,                              /* version */
67         PFD_SUPPORT_OPENGL |
68         PFD_DRAW_TO_WINDOW |
69         PFD_SWAP_COPY |                                 /* support swap copy */
70         PFD_DOUBLEBUFFER,               /* support double-buffering */
71         PFD_TYPE_RGBA,                  /* color type */
72         32,                             /* prefered color depth */
73         0, 0, 0, 0, 0, 0,               /* color bits (ignored) */
74         0,                              /* no alpha buffer */
75         0,                              /* alpha bits (ignored) */
76         0,                              /* no accumulation buffer */
77         0, 0, 0, 0,                     /* accum bits (ignored) */
78         32,                             /* depth buffer */
79         0,                              /* no stencil buffer */
80         0,                              /* no auxiliary buffers */
81         PFD_MAIN_PLANE,                 /* main layer */
82         0,                              /* reserved */
83         0, 0, 0                         /* no layer, visible, damage masks */
84 };
85
86 GHOST_WindowWin32::GHOST_WindowWin32(
87         const STR_String& title,
88         GHOST_TInt32 left,
89         GHOST_TInt32 top,
90         GHOST_TUns32 width,
91         GHOST_TUns32 height,
92         GHOST_TWindowState state,
93         GHOST_TDrawingContextType type,
94         const bool stereoVisual)
95 :
96         GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone,
97         stereoVisual),
98         m_hDC(0),
99         m_hGlRc(0),
100         m_hasMouseCaptured(false),
101         m_nPressedButtons(0),
102         m_customCursor(0)
103 {
104         if (state != GHOST_kWindowStateFullScreen) {
105                         /* Convert client size into window size */
106                 width += GetSystemMetrics(SM_CXSIZEFRAME)*2;
107                 height += GetSystemMetrics(SM_CYSIZEFRAME)*2 + GetSystemMetrics(SM_CYCAPTION);
108
109                 m_hWnd = ::CreateWindow(
110                         s_windowClassName,                      // pointer to registered class name
111                         title,                                          // pointer to window name
112                         WS_OVERLAPPEDWINDOW,            // window style
113                         left,                                           // horizontal position of window
114                         top,                                            // vertical position of window
115                         width,                                          // window width
116                         height,                                         // window height
117                         0,                                                      // handle to parent or owner window
118                         0,                                                      // handle to menu or child-window identifier
119                         ::GetModuleHandle(0),           // handle to application instance
120                         0);                                                     // pointer to window-creation data
121         }
122         else {
123                 m_hWnd = ::CreateWindow(
124                         s_windowClassName,                      // pointer to registered class name
125                         title,                                          // pointer to window name
126                         WS_POPUP | WS_MAXIMIZE,         // window style
127                         left,                                           // horizontal position of window
128                         top,                                            // vertical position of window
129                         width,                                          // window width
130                         height,                                         // window height
131                         0,                                                      // handle to parent or owner window
132                         0,                                                      // handle to menu or child-window identifier
133                         ::GetModuleHandle(0),           // handle to application instance
134                         0);                                                     // pointer to window-creation data
135         }
136         if (m_hWnd) {
137                 // Store a pointer to this class in the window structure
138                 LONG result = ::SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this);
139
140                 // Store the device context
141                 m_hDC = ::GetDC(m_hWnd);
142
143                 // Show the window
144                 int nCmdShow;
145                 switch (state) {
146                         case GHOST_kWindowStateMaximized:
147                                 nCmdShow = SW_SHOWMAXIMIZED;
148                                 break;
149                         case GHOST_kWindowStateMinimized:
150                                 nCmdShow = SW_SHOWMINIMIZED;
151                                 break;
152                         case GHOST_kWindowStateNormal:
153                         default:
154                                 nCmdShow = SW_SHOWNORMAL;
155                                 break;
156                 }
157                 setDrawingContextType(type);
158                 ::ShowWindow(m_hWnd, nCmdShow);
159                 // Force an initial paint of the window
160                 ::UpdateWindow(m_hWnd);
161         }
162 }
163
164
165 GHOST_WindowWin32::~GHOST_WindowWin32()
166 {
167         if (m_customCursor) {
168                 DestroyCursor(m_customCursor);
169                 m_customCursor = NULL;
170         }
171
172         setDrawingContextType(GHOST_kDrawingContextTypeNone);
173         if (m_hDC) {
174                 ::ReleaseDC(m_hWnd, m_hDC);
175                 m_hDC = 0;
176         }
177         if (m_hWnd) {
178                 ::DestroyWindow(m_hWnd);
179                 m_hWnd = 0;
180         }
181 }
182
183 bool GHOST_WindowWin32::getValid() const
184 {
185         return m_hWnd != 0;
186 }
187
188
189 void GHOST_WindowWin32::setTitle(const STR_String& title)
190 {
191         ::SetWindowText(m_hWnd, title);
192 }
193
194
195 void GHOST_WindowWin32::getTitle(STR_String& title) const
196 {
197         char buf[s_maxTitleLength];
198         ::GetWindowText(m_hWnd, buf, s_maxTitleLength);
199         STR_String temp (buf);
200         title = buf;
201 }
202
203
204 void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const
205 {
206         RECT rect;
207         ::GetWindowRect(m_hWnd, &rect);
208         bounds.m_b = rect.bottom;
209         bounds.m_l = rect.left;
210         bounds.m_r = rect.right;
211         bounds.m_t = rect.top;
212 }
213
214
215 void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const
216 {
217         RECT rect;
218         ::GetClientRect(m_hWnd, &rect);
219         bounds.m_b = rect.bottom;
220         bounds.m_l = rect.left;
221         bounds.m_r = rect.right;
222         bounds.m_t = rect.top;
223 }
224
225
226 GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width)
227 {
228         GHOST_TSuccess success;
229         GHOST_Rect cBnds, wBnds;
230         getClientBounds(cBnds);
231         if (cBnds.getWidth() != width) {
232                 getWindowBounds(wBnds);
233                 int cx = wBnds.getWidth() + width - cBnds.getWidth();
234                 int cy = wBnds.getHeight();
235                 success =  ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
236                         GHOST_kSuccess : GHOST_kFailure;
237         }
238         else {
239                 success = GHOST_kSuccess;
240         }
241         return success;
242 }
243
244
245 GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height)
246 {
247         GHOST_TSuccess success;
248         GHOST_Rect cBnds, wBnds;
249         getClientBounds(cBnds);
250         if (cBnds.getHeight() != height) {
251                 getWindowBounds(wBnds);
252                 int cx = wBnds.getWidth();
253                 int cy = wBnds.getHeight() + height - cBnds.getHeight();
254                 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
255                         GHOST_kSuccess : GHOST_kFailure;
256         }
257         else {
258                 success = GHOST_kSuccess;
259         }
260         return success;
261 }
262
263
264 GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
265 {
266         GHOST_TSuccess success;
267         GHOST_Rect cBnds, wBnds;
268         getClientBounds(cBnds);
269         if ((cBnds.getWidth() != width) || (cBnds.getHeight() != height)) {
270                 getWindowBounds(wBnds);
271                 int cx = wBnds.getWidth() + width - cBnds.getWidth();
272                 int cy = wBnds.getHeight() + height - cBnds.getHeight();
273                 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
274                         GHOST_kSuccess : GHOST_kFailure;
275         }
276         else {
277                 success = GHOST_kSuccess;
278         }
279         return success;
280 }
281
282
283 GHOST_TWindowState GHOST_WindowWin32::getState() const
284 {
285         GHOST_TWindowState state;
286         if (::IsIconic(m_hWnd)) {
287                 state = GHOST_kWindowStateMinimized;
288         }
289         else if (::IsZoomed(m_hWnd)) {
290                 state = GHOST_kWindowStateMaximized;
291         }
292         else {
293                 state = GHOST_kWindowStateNormal;
294         }
295         return state;
296 }
297
298
299 void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
300 {
301         POINT point = { inX, inY };
302         ::ScreenToClient(m_hWnd, &point);
303         outX = point.x;
304         outY = point.y;
305 }
306
307
308 void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
309 {
310         POINT point = { inX, inY };
311         ::ClientToScreen(m_hWnd, &point);
312         outX = point.x;
313         outY = point.y;
314 }
315
316
317 GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
318 {
319         WINDOWPLACEMENT wp;
320         wp.length = sizeof(WINDOWPLACEMENT);
321         ::GetWindowPlacement(m_hWnd, &wp);
322         switch (state) {
323         case GHOST_kWindowStateMinimized: 
324                 wp.showCmd = SW_SHOWMINIMIZED; 
325                 break;
326         case GHOST_kWindowStateMaximized: 
327                 ShowWindow(m_hWnd, SW_HIDE); //fe. HACK!
328                                 //Solves redraw problems when switching from fullscreen to normal.
329                                 
330                 wp.showCmd = SW_SHOWMAXIMIZED; 
331                 SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
332                 break;
333         case GHOST_kWindowStateFullScreen:
334                 wp.showCmd = SW_SHOWMAXIMIZED;
335                 SetWindowLong(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
336                 break;
337         case GHOST_kWindowStateNormal: 
338         default: 
339                 wp.showCmd = SW_SHOWNORMAL; 
340                 break;
341         }
342         return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
343 }
344
345
346 GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
347 {
348         HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM;
349         return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
350 }
351
352
353 GHOST_TSuccess GHOST_WindowWin32::swapBuffers()
354 {
355         // adding a glFinish() here is to prevent Geforce in 'full scene antialias' mode
356         // from antialising the Blender window. Officially a swapbuffers does a glFinish
357         // itself, so this feels really like a hack... but it won't harm. (ton)
358         glFinish();
359         return ::SwapBuffers(m_hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
360 }
361
362
363 GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext()
364 {
365         GHOST_TSuccess success;
366         if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
367                 if (m_hDC && m_hGlRc) {
368                         success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
369                 }
370                 else {
371                         success = GHOST_kFailure;
372                 }
373         }
374         else {
375                 success = GHOST_kSuccess;
376         }
377         return success;
378 }
379
380
381 GHOST_TSuccess GHOST_WindowWin32::invalidate()
382 {
383         GHOST_TSuccess success;
384         if (m_hWnd) {
385                 success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
386         }
387         else {
388                 success = GHOST_kFailure;
389         }
390         return success;
391 }
392
393
394 GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type)
395 {
396         GHOST_TSuccess success;
397         switch (type) {
398         case GHOST_kDrawingContextTypeOpenGL:
399                 {
400                 if(m_stereoVisual) 
401                         sPreferredFormat.dwFlags |= PFD_STEREO;
402
403                 // Attempt to match device context pixel format to the preferred format
404                 int iPixelFormat = EnumPixelFormats(m_hDC);
405                 if (iPixelFormat == 0) {
406                         success = GHOST_kFailure;
407                         break;
408                 }
409                 if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) {
410                         success = GHOST_kFailure;
411                         break;
412                 }
413                 // For debugging only: retrieve the pixel format chosen
414                 PIXELFORMATDESCRIPTOR preferredFormat;
415                 ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat);
416                 // Create the context
417                 m_hGlRc = ::wglCreateContext(m_hDC);
418                 if (m_hGlRc) {
419                         if (s_firsthGLRc) {
420                                 wglShareLists(s_firsthGLRc, m_hGlRc);
421                         } else {
422                                 s_firsthGLRc = m_hGlRc;
423                         }
424
425                         success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
426                 }
427                 else {
428                         success = GHOST_kFailure;
429                 }
430                 }
431                 break;
432
433         case GHOST_kDrawingContextTypeNone:
434                 success = GHOST_kSuccess;
435                 break;
436
437         default:
438                 success = GHOST_kFailure;
439         }
440         return success;
441 }
442
443
444 GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext()
445 {
446         GHOST_TSuccess success;
447         switch (m_drawingContextType) {
448         case GHOST_kDrawingContextTypeOpenGL:
449                 if (m_hGlRc) {
450                         success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
451                         if (m_hGlRc == s_firsthGLRc) {
452                                 s_firsthGLRc = NULL;
453                         }
454                         m_hGlRc = 0;
455                 }
456                 else {
457                         success = GHOST_kFailure;
458                 }
459                 break;
460         case GHOST_kDrawingContextTypeNone:
461                 success = GHOST_kSuccess;
462                 break;
463         default:
464                 success = GHOST_kFailure;
465         }
466         return success;
467 }
468
469 void GHOST_WindowWin32::lostMouseCapture()
470 {
471         if (m_hasMouseCaptured) {
472                 m_hasMouseCaptured = false;
473                 m_nPressedButtons = 0;
474         }
475 }
476
477 void GHOST_WindowWin32::registerMouseClickEvent(bool press)
478 {
479         if (press) {
480                 if (!m_hasMouseCaptured) {
481                         ::SetCapture(m_hWnd);
482                         m_hasMouseCaptured = true;
483                 }
484                 m_nPressedButtons++;
485         } else {
486                 if (m_nPressedButtons) {
487                         m_nPressedButtons--;
488                         if (!m_nPressedButtons) {
489                                 ::ReleaseCapture();
490                                 m_hasMouseCaptured = false;
491                         }
492                 }
493         }
494 }
495
496
497 void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
498 {
499         if (!visible) {
500                 while (::ShowCursor(FALSE) >= 0);
501         }
502         else {
503                 while (::ShowCursor(TRUE) < 0);
504         }
505
506         if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
507                 ::SetCursor( m_customCursor );
508         } else {
509                 // Convert GHOST cursor to Windows OEM cursor
510                 bool success = true;
511                 LPCSTR id;
512                 switch (cursor) {
513                         case GHOST_kStandardCursorDefault:              id = IDC_ARROW;         break;
514                         case GHOST_kStandardCursorRightArrow:           id = IDC_ARROW;         break;
515                         case GHOST_kStandardCursorLeftArrow:            id = IDC_ARROW;         break;
516                         case GHOST_kStandardCursorInfo:                 id = IDC_SIZEALL;       break;  // Four-pointed arrow pointing north, south, east, and west
517                         case GHOST_kStandardCursorDestroy:              id = IDC_NO;            break;  // Slashed circle
518                         case GHOST_kStandardCursorHelp:                 id = IDC_HELP;          break;  // Arrow and question mark
519                         case GHOST_kStandardCursorCycle:                id = IDC_NO;            break;  // Slashed circle
520                         case GHOST_kStandardCursorSpray:                id = IDC_SIZEALL;       break;  // Four-pointed arrow pointing north, south, east, and west
521                         case GHOST_kStandardCursorWait:                 id = IDC_WAIT;          break;  // Hourglass
522                         case GHOST_kStandardCursorText:                 id = IDC_IBEAM;         break;  // I-beam
523                         case GHOST_kStandardCursorCrosshair:            id = IDC_CROSS;         break;  // Crosshair
524                         case GHOST_kStandardCursorUpDown:               id = IDC_SIZENS;        break;  // Double-pointed arrow pointing north and south
525                         case GHOST_kStandardCursorLeftRight:            id = IDC_SIZEWE;        break;  // Double-pointed arrow pointing west and east
526                         case GHOST_kStandardCursorTopSide:              id = IDC_UPARROW;       break;  // Vertical arrow
527                         case GHOST_kStandardCursorBottomSide:           id = IDC_SIZENS;        break;
528                         case GHOST_kStandardCursorLeftSide:             id = IDC_SIZEWE;        break;
529                         case GHOST_kStandardCursorTopLeftCorner:        id = IDC_SIZENWSE;      break;
530                         case GHOST_kStandardCursorTopRightCorner:       id = IDC_SIZENESW;      break;
531                         case GHOST_kStandardCursorBottomRightCorner:    id = IDC_SIZENWSE;      break;
532                         case GHOST_kStandardCursorBottomLeftCorner:     id = IDC_SIZENESW;      break;
533                         case GHOST_kStandardCursorPencil:               id = IDC_ARROW;         break;
534                         default:
535                         success = false;
536                 }
537                 
538                 if (success) {
539                         HCURSOR hCursor = ::SetCursor(::LoadCursor(0, id));
540                 }
541         }
542 }
543
544 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
545 {
546         if (::GetForegroundWindow() == m_hWnd) {
547                 loadCursor(visible, getCursorShape());
548         }
549
550         return GHOST_kSuccess;
551 }
552
553 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
554 {
555         if (m_customCursor) {
556                 DestroyCursor(m_customCursor);
557                 m_customCursor = NULL;
558         }
559
560         if (::GetForegroundWindow() == m_hWnd) {
561                 loadCursor(getCursorVisibility(), cursorShape);
562         }
563
564         return GHOST_kSuccess;
565 }
566
567 /** Reverse the bits in a GHOST_TUns8 */
568 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
569 {
570         ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
571         ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
572         ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
573         return ch;
574 }
575
576 /** Reverse the bits in a GHOST_TUns16 */
577 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
578 {
579         shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
580         shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
581         shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
582         shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
583         return shrt;
584 }
585 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 
586                                         GHOST_TUns8 mask[16][2], int hotX, int hotY)
587 {
588         return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, 
589                                                                         16, 16, hotX, hotY, 0, 1);
590 }
591
592 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, 
593                                         GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY, 
594                                         int fg_color, int bg_color)
595 {
596         GHOST_TUns32 andData[32];
597         GHOST_TUns32 xorData[32];
598         GHOST_TUns32 fullBitRow, fullMaskRow;
599         int x, y, cols;
600         
601         cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */
602         if (sizeX%8) cols++;
603         
604         if (m_customCursor) {
605                 DestroyCursor(m_customCursor);
606                 m_customCursor = NULL;
607         }
608
609         memset(&andData, 0xFF, sizeof(andData));
610         memset(&xorData, 0, sizeof(xorData));
611
612         for (y=0; y<sizeY; y++) {
613                 fullBitRow=0;
614                 fullMaskRow=0;
615                 for (x=cols-1; x>=0; x--){
616                         fullBitRow<<=8;
617                         fullMaskRow<<=8;
618                         fullBitRow  |= uns8ReverseBits(bitmap[cols*y + x]);
619                         fullMaskRow |= uns8ReverseBits(  mask[cols*y + x]);
620                 }
621                 xorData[y]= fullBitRow & fullMaskRow;
622                 andData[y]= ~fullMaskRow;
623         }
624
625         m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
626         if (!m_customCursor) {
627                 return GHOST_kFailure;
628         }
629
630         if (::GetForegroundWindow() == m_hWnd) {
631                 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
632         }
633
634         return GHOST_kSuccess;
635 }
636
637
638 /*  Ron Fosner's code for weighting pixel formats and forcing software.
639         See http://www.opengl.org/resources/faq/technical/weight.cpp */
640
641 static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) {
642         int weight = 0;
643         
644         /* assume desktop color depth is 32 bits per pixel */
645         
646         /* cull unusable pixel formats */
647         /* if no formats can be found, can we determine why it was rejected? */
648         if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) ||
649                 !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
650                 !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
651                 ( pfd.cDepthBits <= 8 ) ||
652                 !(pfd.iPixelType == PFD_TYPE_RGBA) )
653                 return 0;
654         
655         weight = 1;  /* it's usable */
656         
657         /* the bigger the depth buffer the better */
658         /* give no weight to a 16-bit depth buffer, because those are crap */
659         weight += pfd.cDepthBits - 16;
660         
661         weight += pfd.cColorBits - 8;
662         
663         /* want swap copy capability -- it matters a lot */
664         if(pfd.dwFlags & PFD_SWAP_COPY) weight += 16;
665         
666         /* but if it's a generic (not accelerated) view, it's really bad */
667         if(pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10;
668         
669         return weight;
670 }
671
672 /* A modification of Ron Fosner's replacement for ChoosePixelFormat */ 
673 /* returns 0 on error, else returns the pixel format number to be used */
674 static int EnumPixelFormats(HDC hdc) {
675         int iPixelFormat;
676         int i, n, w, weight = 0;
677         PIXELFORMATDESCRIPTOR pfd, pfd_fallback;
678         
679         /* we need a device context to do anything */
680         if(!hdc) return 0;
681
682         iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */
683         
684         /* obtain detailed information about 
685         the device context's first pixel format */
686         n = 1+::DescribePixelFormat(hdc, iPixelFormat, 
687                 sizeof(PIXELFORMATDESCRIPTOR), &pfd);
688         
689         /* choose a pixel format using the useless Windows function in case
690                 we come up empty handed */
691         iPixelFormat = ::ChoosePixelFormat( hdc, &sPreferredFormat );
692         
693         if(!iPixelFormat) return 0; /* couldn't find one to use */
694
695         for(i=1; i<=n; i++) { /* not the idiom, but it's right */
696                 ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
697                 w = WeightPixelFormat(pfd);
698                 if(w > weight) {
699                         weight = w;
700                         iPixelFormat = i;
701                 }
702         }
703         
704         return iPixelFormat;
705 }
706
707