~diresu/blender/blender-command-port

« back to all changes in this revision

Viewing changes to intern/ghost/intern/GHOST_WindowWin32.cpp

  • Committer: theeth
  • Date: 2008-10-14 16:52:04 UTC
  • Revision ID: vcs-imports@canonical.com-20081014165204-r32w2gm6s0osvdhn
copy back trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * $Id: GHOST_WindowWin32.cpp 17019 2008-10-11 16:03:17Z blendix $
 
3
 * ***** BEGIN GPL 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.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software Foundation,
 
17
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
18
 *
 
19
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 
20
 * All rights reserved.
 
21
 *
 
22
 * The Original Code is: all of this file.
 
23
 *
 
24
 * Contributor(s): none yet.
 
25
 *
 
26
 * ***** END GPL LICENSE BLOCK *****
 
27
 */
 
28
 
 
29
/**
 
30
 
 
31
 * $Id: GHOST_WindowWin32.cpp 17019 2008-10-11 16:03:17Z blendix $
 
32
 * Copyright (C) 2001 NaN Technologies B.V.
 
33
 * @author      Maarten Gribnau
 
34
 * @date        May 10, 2001
 
35
 */
 
36
 
 
37
#ifdef HAVE_CONFIG_H
 
38
#include <config.h>
 
39
#endif
 
40
 
 
41
#include <string.h>
 
42
#include "GHOST_WindowWin32.h"
 
43
#include <GL/gl.h>
 
44
#include <math.h>
 
45
 
 
46
// MSVC6 still doesn't define M_PI
 
47
#ifndef M_PI
 
48
#define M_PI 3.1415926536
 
49
#endif
 
50
 
 
51
// win64 doesn't define GWL_USERDATA
 
52
#ifdef WIN32
 
53
#ifndef GWL_USERDATA
 
54
#define GWL_USERDATA GWLP_USERDATA
 
55
#define GWL_WNDPROC GWLP_WNDPROC
 
56
#endif
 
57
#endif
 
58
 
 
59
LPCSTR GHOST_WindowWin32::s_windowClassName = "GHOST_WindowClass";
 
60
const int GHOST_WindowWin32::s_maxTitleLength = 128;
 
61
HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL;
 
62
 
 
63
static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd);
 
64
static int EnumPixelFormats(HDC hdc);
 
65
 
 
66
/*
 
67
 * Color and depth bit values are not to be trusted.
 
68
 * For instance, on TNT2:
 
69
 * When the screen color depth is set to 16 bit, we get 5 color bits
 
70
 * and 16 depth bits.
 
71
 * When the screen color depth is set to 32 bit, we get 8 color bits
 
72
 * and 24 depth bits.
 
73
 * Just to be safe, we request high waulity settings.
 
74
 */
 
75
static PIXELFORMATDESCRIPTOR sPreferredFormat = {
 
76
        sizeof(PIXELFORMATDESCRIPTOR),  /* size */
 
77
        1,                              /* version */
 
78
        PFD_SUPPORT_OPENGL |
 
79
        PFD_DRAW_TO_WINDOW |
 
80
        PFD_SWAP_COPY |                                 /* support swap copy */
 
81
        PFD_DOUBLEBUFFER,               /* support double-buffering */
 
82
        PFD_TYPE_RGBA,                  /* color type */
 
83
        32,                             /* prefered color depth */
 
84
        0, 0, 0, 0, 0, 0,               /* color bits (ignored) */
 
85
        0,                              /* no alpha buffer */
 
86
        0,                              /* alpha bits (ignored) */
 
87
        0,                              /* no accumulation buffer */
 
88
        0, 0, 0, 0,                     /* accum bits (ignored) */
 
89
        32,                             /* depth buffer */
 
90
        0,                              /* no stencil buffer */
 
91
        0,                              /* no auxiliary buffers */
 
92
        PFD_MAIN_PLANE,                 /* main layer */
 
93
        0,                              /* reserved */
 
94
        0, 0, 0                         /* no layer, visible, damage masks */
 
95
};
 
96
 
 
97
GHOST_WindowWin32::GHOST_WindowWin32(
 
98
        const STR_String& title,
 
99
        GHOST_TInt32 left,
 
100
        GHOST_TInt32 top,
 
101
        GHOST_TUns32 width,
 
102
        GHOST_TUns32 height,
 
103
        GHOST_TWindowState state,
 
104
        GHOST_TDrawingContextType type,
 
105
        const bool stereoVisual)
 
106
:
 
107
        GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone,
 
108
        stereoVisual),
 
109
        m_hDC(0),
 
110
        m_hGlRc(0),
 
111
        m_hasMouseCaptured(false),
 
112
        m_nPressedButtons(0),
 
113
        m_customCursor(0),
 
114
        m_tabletData(NULL),
 
115
        m_tablet(0),
 
116
        m_wintab(NULL),
 
117
        m_maxPressure(0)
 
118
{
 
119
        if (state != GHOST_kWindowStateFullScreen) {
 
120
                        /* Convert client size into window size */
 
121
                width += GetSystemMetrics(SM_CXSIZEFRAME)*2;
 
122
                height += GetSystemMetrics(SM_CYSIZEFRAME)*2 + GetSystemMetrics(SM_CYCAPTION);
 
123
 
 
124
                m_hWnd = ::CreateWindow(
 
125
                        s_windowClassName,                      // pointer to registered class name
 
126
                        title,                                          // pointer to window name
 
127
                        WS_OVERLAPPEDWINDOW,            // window style
 
128
                        left,                                           // horizontal position of window
 
129
                        top,                                            // vertical position of window
 
130
                        width,                                          // window width
 
131
                        height,                                         // window height
 
132
                        0,                                                      // handle to parent or owner window
 
133
                        0,                                                      // handle to menu or child-window identifier
 
134
                        ::GetModuleHandle(0),           // handle to application instance
 
135
                        0);                                                     // pointer to window-creation data
 
136
        }
 
137
        else {
 
138
                m_hWnd = ::CreateWindow(
 
139
                        s_windowClassName,                      // pointer to registered class name
 
140
                        title,                                          // pointer to window name
 
141
                        WS_POPUP | WS_MAXIMIZE,         // window style
 
142
                        left,                                           // horizontal position of window
 
143
                        top,                                            // vertical position of window
 
144
                        width,                                          // window width
 
145
                        height,                                         // window height
 
146
                        0,                                                      // handle to parent or owner window
 
147
                        0,                                                      // handle to menu or child-window identifier
 
148
                        ::GetModuleHandle(0),           // handle to application instance
 
149
                        0);                                                     // pointer to window-creation data
 
150
        }
 
151
        if (m_hWnd) {
 
152
                // Store a pointer to this class in the window structure
 
153
                LONG result = ::SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this);
 
154
 
 
155
                // Store the device context
 
156
                m_hDC = ::GetDC(m_hWnd);
 
157
 
 
158
                // Show the window
 
159
                int nCmdShow;
 
160
                switch (state) {
 
161
                        case GHOST_kWindowStateMaximized:
 
162
                                nCmdShow = SW_SHOWMAXIMIZED;
 
163
                                break;
 
164
                        case GHOST_kWindowStateMinimized:
 
165
                                nCmdShow = SW_SHOWMINIMIZED;
 
166
                                break;
 
167
                        case GHOST_kWindowStateNormal:
 
168
                        default:
 
169
                                nCmdShow = SW_SHOWNORMAL;
 
170
                                break;
 
171
                }
 
172
                setDrawingContextType(type);
 
173
                ::ShowWindow(m_hWnd, nCmdShow);
 
174
                // Force an initial paint of the window
 
175
                ::UpdateWindow(m_hWnd);
 
176
        }
 
177
 
 
178
        m_wintab = ::LoadLibrary("Wintab32.dll");
 
179
        if (m_wintab) {
 
180
                GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
 
181
                GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" );
 
182
 
 
183
                // let's see if we can initialize tablet here
 
184
                /* check if WinTab available. */
 
185
                if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
 
186
                        // Now init the tablet
 
187
                        LOGCONTEXT lc;
 
188
                        AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */
 
189
 
 
190
                        // Open a Wintab context
 
191
 
 
192
                        // Get default context information
 
193
                        fpWTInfo( WTI_DEFCONTEXT, 0, &lc );
 
194
 
 
195
                        // Open the context
 
196
                        lc.lcPktData = PACKETDATA;
 
197
                        lc.lcPktMode = PACKETMODE;
 
198
                        lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;
 
199
 
 
200
                        /* Set the entire tablet as active */
 
201
                        fpWTInfo(WTI_DEVICES,DVC_X,&TabletX);
 
202
                        fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY);
 
203
 
 
204
                        /* get the max pressure, to divide into a float */
 
205
                        BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
 
206
                        if (pressureSupport)
 
207
                                m_maxPressure = Pressure.axMax;
 
208
                        else
 
209
                                m_maxPressure = 0;
 
210
 
 
211
                        /* get the max tilt axes, to divide into floats */
 
212
                        BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation);
 
213
                        if (tiltSupport) {
 
214
                                /* does the tablet support azimuth ([0]) and altitude ([1]) */
 
215
                                if (Orientation[0].axResolution && Orientation[1].axResolution) {
 
216
                                        /* all this assumes the minimum is 0 */
 
217
                                        m_maxAzimuth = Orientation[0].axMax;
 
218
                                        m_maxAltitude = Orientation[1].axMax;
 
219
                                }
 
220
                                else {  /* no so dont do tilt stuff */
 
221
                                        m_maxAzimuth = m_maxAltitude = 0;
 
222
                                }
 
223
                        }
 
224
 
 
225
                        if (fpWTOpen) {
 
226
                                m_tablet = fpWTOpen( m_hWnd, &lc, TRUE );
 
227
                                if (m_tablet) {
 
228
                                        m_tabletData = new GHOST_TabletData();
 
229
                                        m_tabletData->Active = 0;
 
230
                                }
 
231
                        }
 
232
                }
 
233
        }
 
234
}
 
235
 
 
236
 
 
237
GHOST_WindowWin32::~GHOST_WindowWin32()
 
238
{
 
239
        if (m_wintab) {
 
240
                GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" );
 
241
                if (fpWTClose) {
 
242
                        if (m_tablet) 
 
243
                                fpWTClose(m_tablet);
 
244
                        if (m_tabletData)
 
245
                                delete m_tabletData;
 
246
                                m_tabletData = NULL;
 
247
                }
 
248
        }
 
249
        if (m_customCursor) {
 
250
                DestroyCursor(m_customCursor);
 
251
                m_customCursor = NULL;
 
252
        }
 
253
 
 
254
        setDrawingContextType(GHOST_kDrawingContextTypeNone);
 
255
        if (m_hDC) {
 
256
                ::ReleaseDC(m_hWnd, m_hDC);
 
257
                m_hDC = 0;
 
258
        }
 
259
        if (m_hWnd) {
 
260
                ::DestroyWindow(m_hWnd);
 
261
                m_hWnd = 0;
 
262
        }
 
263
}
 
264
 
 
265
bool GHOST_WindowWin32::getValid() const
 
266
{
 
267
        return m_hWnd != 0;
 
268
}
 
269
 
 
270
 
 
271
void GHOST_WindowWin32::setTitle(const STR_String& title)
 
272
{
 
273
        ::SetWindowText(m_hWnd, title);
 
274
}
 
275
 
 
276
 
 
277
void GHOST_WindowWin32::getTitle(STR_String& title) const
 
278
{
 
279
        char buf[s_maxTitleLength];
 
280
        ::GetWindowText(m_hWnd, buf, s_maxTitleLength);
 
281
        STR_String temp (buf);
 
282
        title = buf;
 
283
}
 
284
 
 
285
 
 
286
void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const
 
287
{
 
288
        RECT rect;
 
289
        ::GetWindowRect(m_hWnd, &rect);
 
290
        bounds.m_b = rect.bottom;
 
291
        bounds.m_l = rect.left;
 
292
        bounds.m_r = rect.right;
 
293
        bounds.m_t = rect.top;
 
294
}
 
295
 
 
296
 
 
297
void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const
 
298
{
 
299
        RECT rect;
 
300
        ::GetClientRect(m_hWnd, &rect);
 
301
        bounds.m_b = rect.bottom;
 
302
        bounds.m_l = rect.left;
 
303
        bounds.m_r = rect.right;
 
304
        bounds.m_t = rect.top;
 
305
}
 
306
 
 
307
 
 
308
GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width)
 
309
{
 
310
        GHOST_TSuccess success;
 
311
        GHOST_Rect cBnds, wBnds;
 
312
        getClientBounds(cBnds);
 
313
        if (cBnds.getWidth() != width) {
 
314
                getWindowBounds(wBnds);
 
315
                int cx = wBnds.getWidth() + width - cBnds.getWidth();
 
316
                int cy = wBnds.getHeight();
 
317
                success =  ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
 
318
                        GHOST_kSuccess : GHOST_kFailure;
 
319
        }
 
320
        else {
 
321
                success = GHOST_kSuccess;
 
322
        }
 
323
        return success;
 
324
}
 
325
 
 
326
 
 
327
GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height)
 
328
{
 
329
        GHOST_TSuccess success;
 
330
        GHOST_Rect cBnds, wBnds;
 
331
        getClientBounds(cBnds);
 
332
        if (cBnds.getHeight() != height) {
 
333
                getWindowBounds(wBnds);
 
334
                int cx = wBnds.getWidth();
 
335
                int cy = wBnds.getHeight() + height - cBnds.getHeight();
 
336
                success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
 
337
                        GHOST_kSuccess : GHOST_kFailure;
 
338
        }
 
339
        else {
 
340
                success = GHOST_kSuccess;
 
341
        }
 
342
        return success;
 
343
}
 
344
 
 
345
 
 
346
GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
 
347
{
 
348
        GHOST_TSuccess success;
 
349
        GHOST_Rect cBnds, wBnds;
 
350
        getClientBounds(cBnds);
 
351
        if ((cBnds.getWidth() != width) || (cBnds.getHeight() != height)) {
 
352
                getWindowBounds(wBnds);
 
353
                int cx = wBnds.getWidth() + width - cBnds.getWidth();
 
354
                int cy = wBnds.getHeight() + height - cBnds.getHeight();
 
355
                success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
 
356
                        GHOST_kSuccess : GHOST_kFailure;
 
357
        }
 
358
        else {
 
359
                success = GHOST_kSuccess;
 
360
        }
 
361
        return success;
 
362
}
 
363
 
 
364
 
 
365
GHOST_TWindowState GHOST_WindowWin32::getState() const
 
366
{
 
367
        GHOST_TWindowState state;
 
368
        if (::IsIconic(m_hWnd)) {
 
369
                state = GHOST_kWindowStateMinimized;
 
370
        }
 
371
        else if (::IsZoomed(m_hWnd)) {
 
372
                state = GHOST_kWindowStateMaximized;
 
373
        }
 
374
        else {
 
375
                state = GHOST_kWindowStateNormal;
 
376
        }
 
377
        return state;
 
378
}
 
379
 
 
380
 
 
381
void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
 
382
{
 
383
        POINT point = { inX, inY };
 
384
        ::ScreenToClient(m_hWnd, &point);
 
385
        outX = point.x;
 
386
        outY = point.y;
 
387
}
 
388
 
 
389
 
 
390
void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
 
391
{
 
392
        POINT point = { inX, inY };
 
393
        ::ClientToScreen(m_hWnd, &point);
 
394
        outX = point.x;
 
395
        outY = point.y;
 
396
}
 
397
 
 
398
 
 
399
GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
 
400
{
 
401
        WINDOWPLACEMENT wp;
 
402
        wp.length = sizeof(WINDOWPLACEMENT);
 
403
        ::GetWindowPlacement(m_hWnd, &wp);
 
404
        switch (state) {
 
405
        case GHOST_kWindowStateMinimized: 
 
406
                wp.showCmd = SW_SHOWMINIMIZED; 
 
407
                break;
 
408
        case GHOST_kWindowStateMaximized: 
 
409
                ShowWindow(m_hWnd, SW_HIDE); //fe. HACK!
 
410
                                //Solves redraw problems when switching from fullscreen to normal.
 
411
                                
 
412
                wp.showCmd = SW_SHOWMAXIMIZED; 
 
413
                SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
 
414
                break;
 
415
        case GHOST_kWindowStateFullScreen:
 
416
                wp.showCmd = SW_SHOWMAXIMIZED;
 
417
                SetWindowLong(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
 
418
                break;
 
419
        case GHOST_kWindowStateNormal: 
 
420
        default: 
 
421
                wp.showCmd = SW_SHOWNORMAL; 
 
422
                break;
 
423
        }
 
424
        return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
 
425
}
 
426
 
 
427
 
 
428
GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
 
429
{
 
430
        HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM;
 
431
        return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
 
432
}
 
433
 
 
434
 
 
435
GHOST_TSuccess GHOST_WindowWin32::swapBuffers()
 
436
{
 
437
        return ::SwapBuffers(m_hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
 
438
}
 
439
 
 
440
 
 
441
GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext()
 
442
{
 
443
        GHOST_TSuccess success;
 
444
        if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
 
445
                if (m_hDC && m_hGlRc) {
 
446
                        success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
 
447
                }
 
448
                else {
 
449
                        success = GHOST_kFailure;
 
450
                }
 
451
        }
 
452
        else {
 
453
                success = GHOST_kSuccess;
 
454
        }
 
455
        return success;
 
456
}
 
457
 
 
458
 
 
459
GHOST_TSuccess GHOST_WindowWin32::invalidate()
 
460
{
 
461
        GHOST_TSuccess success;
 
462
        if (m_hWnd) {
 
463
                success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
 
464
        }
 
465
        else {
 
466
                success = GHOST_kFailure;
 
467
        }
 
468
        return success;
 
469
}
 
470
 
 
471
 
 
472
GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type)
 
473
{
 
474
        GHOST_TSuccess success;
 
475
        switch (type) {
 
476
        case GHOST_kDrawingContextTypeOpenGL:
 
477
                {
 
478
                if(m_stereoVisual) 
 
479
                        sPreferredFormat.dwFlags |= PFD_STEREO;
 
480
 
 
481
                // Attempt to match device context pixel format to the preferred format
 
482
                int iPixelFormat = EnumPixelFormats(m_hDC);
 
483
                if (iPixelFormat == 0) {
 
484
                        success = GHOST_kFailure;
 
485
                        break;
 
486
                }
 
487
                if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) {
 
488
                        success = GHOST_kFailure;
 
489
                        break;
 
490
                }
 
491
                // For debugging only: retrieve the pixel format chosen
 
492
                PIXELFORMATDESCRIPTOR preferredFormat;
 
493
                ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat);
 
494
                // Create the context
 
495
                m_hGlRc = ::wglCreateContext(m_hDC);
 
496
                if (m_hGlRc) {
 
497
                        if (s_firsthGLRc) {
 
498
                                wglShareLists(s_firsthGLRc, m_hGlRc);
 
499
                        } else {
 
500
                                s_firsthGLRc = m_hGlRc;
 
501
                        }
 
502
 
 
503
                        success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
 
504
                }
 
505
                else {
 
506
                        success = GHOST_kFailure;
 
507
                }
 
508
                }
 
509
                break;
 
510
 
 
511
        case GHOST_kDrawingContextTypeNone:
 
512
                success = GHOST_kSuccess;
 
513
                break;
 
514
 
 
515
        default:
 
516
                success = GHOST_kFailure;
 
517
        }
 
518
        return success;
 
519
}
 
520
 
 
521
 
 
522
GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext()
 
523
{
 
524
        GHOST_TSuccess success;
 
525
        switch (m_drawingContextType) {
 
526
        case GHOST_kDrawingContextTypeOpenGL:
 
527
                if (m_hGlRc) {
 
528
                        success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
 
529
                        if (m_hGlRc == s_firsthGLRc) {
 
530
                                s_firsthGLRc = NULL;
 
531
                        }
 
532
                        m_hGlRc = 0;
 
533
                }
 
534
                else {
 
535
                        success = GHOST_kFailure;
 
536
                }
 
537
                break;
 
538
        case GHOST_kDrawingContextTypeNone:
 
539
                success = GHOST_kSuccess;
 
540
                break;
 
541
        default:
 
542
                success = GHOST_kFailure;
 
543
        }
 
544
        return success;
 
545
}
 
546
 
 
547
void GHOST_WindowWin32::lostMouseCapture()
 
548
{
 
549
        if (m_hasMouseCaptured) {
 
550
                m_hasMouseCaptured = false;
 
551
                m_nPressedButtons = 0;
 
552
        }
 
553
}
 
554
 
 
555
void GHOST_WindowWin32::registerMouseClickEvent(bool press)
 
556
{
 
557
        if (press) {
 
558
                if (!m_hasMouseCaptured) {
 
559
                        ::SetCapture(m_hWnd);
 
560
                        m_hasMouseCaptured = true;
 
561
                }
 
562
                m_nPressedButtons++;
 
563
        } else {
 
564
                if (m_nPressedButtons) {
 
565
                        m_nPressedButtons--;
 
566
                        if (!m_nPressedButtons) {
 
567
                                ::ReleaseCapture();
 
568
                                m_hasMouseCaptured = false;
 
569
                        }
 
570
                }
 
571
        }
 
572
}
 
573
 
 
574
 
 
575
void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
 
576
{
 
577
        if (!visible) {
 
578
                while (::ShowCursor(FALSE) >= 0);
 
579
        }
 
580
        else {
 
581
                while (::ShowCursor(TRUE) < 0);
 
582
        }
 
583
 
 
584
        if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
 
585
                ::SetCursor( m_customCursor );
 
586
        } else {
 
587
                // Convert GHOST cursor to Windows OEM cursor
 
588
                bool success = true;
 
589
                LPCSTR id;
 
590
                switch (cursor) {
 
591
                        case GHOST_kStandardCursorDefault:              id = IDC_ARROW;         break;
 
592
                        case GHOST_kStandardCursorRightArrow:           id = IDC_ARROW;         break;
 
593
                        case GHOST_kStandardCursorLeftArrow:            id = IDC_ARROW;         break;
 
594
                        case GHOST_kStandardCursorInfo:                 id = IDC_SIZEALL;       break;  // Four-pointed arrow pointing north, south, east, and west
 
595
                        case GHOST_kStandardCursorDestroy:              id = IDC_NO;            break;  // Slashed circle
 
596
                        case GHOST_kStandardCursorHelp:                 id = IDC_HELP;          break;  // Arrow and question mark
 
597
                        case GHOST_kStandardCursorCycle:                id = IDC_NO;            break;  // Slashed circle
 
598
                        case GHOST_kStandardCursorSpray:                id = IDC_SIZEALL;       break;  // Four-pointed arrow pointing north, south, east, and west
 
599
                        case GHOST_kStandardCursorWait:                 id = IDC_WAIT;          break;  // Hourglass
 
600
                        case GHOST_kStandardCursorText:                 id = IDC_IBEAM;         break;  // I-beam
 
601
                        case GHOST_kStandardCursorCrosshair:            id = IDC_CROSS;         break;  // Crosshair
 
602
                        case GHOST_kStandardCursorUpDown:               id = IDC_SIZENS;        break;  // Double-pointed arrow pointing north and south
 
603
                        case GHOST_kStandardCursorLeftRight:            id = IDC_SIZEWE;        break;  // Double-pointed arrow pointing west and east
 
604
                        case GHOST_kStandardCursorTopSide:              id = IDC_UPARROW;       break;  // Vertical arrow
 
605
                        case GHOST_kStandardCursorBottomSide:           id = IDC_SIZENS;        break;
 
606
                        case GHOST_kStandardCursorLeftSide:             id = IDC_SIZEWE;        break;
 
607
                        case GHOST_kStandardCursorTopLeftCorner:        id = IDC_SIZENWSE;      break;
 
608
                        case GHOST_kStandardCursorTopRightCorner:       id = IDC_SIZENESW;      break;
 
609
                        case GHOST_kStandardCursorBottomRightCorner:    id = IDC_SIZENWSE;      break;
 
610
                        case GHOST_kStandardCursorBottomLeftCorner:     id = IDC_SIZENESW;      break;
 
611
                        case GHOST_kStandardCursorPencil:               id = IDC_ARROW;         break;
 
612
                        default:
 
613
                        success = false;
 
614
                }
 
615
                
 
616
                if (success) {
 
617
                        HCURSOR hCursor = ::SetCursor(::LoadCursor(0, id));
 
618
                }
 
619
        }
 
620
}
 
621
 
 
622
GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
 
623
{
 
624
        if (::GetForegroundWindow() == m_hWnd) {
 
625
                loadCursor(visible, getCursorShape());
 
626
        }
 
627
 
 
628
        return GHOST_kSuccess;
 
629
}
 
630
 
 
631
GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
 
632
{
 
633
        if (m_customCursor) {
 
634
                DestroyCursor(m_customCursor);
 
635
                m_customCursor = NULL;
 
636
        }
 
637
 
 
638
        if (::GetForegroundWindow() == m_hWnd) {
 
639
                loadCursor(getCursorVisibility(), cursorShape);
 
640
        }
 
641
 
 
642
        return GHOST_kSuccess;
 
643
}
 
644
void GHOST_WindowWin32::processWin32TabletInitEvent()
 
645
{
 
646
        if (m_wintab) {
 
647
                GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
 
648
                
 
649
                // let's see if we can initialize tablet here
 
650
                /* check if WinTab available. */
 
651
                if (fpWTInfo) {
 
652
                        AXIS Pressure, Orientation[3]; /* The maximum tablet size */
 
653
 
 
654
                        BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
 
655
                        if (pressureSupport)
 
656
                                m_maxPressure = Pressure.axMax;
 
657
                        else
 
658
                                m_maxPressure = 0;
 
659
                        
 
660
                        BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation);
 
661
                        if (tiltSupport) {
 
662
                                /* does the tablet support azimuth ([0]) and altitude ([1]) */
 
663
                                if (Orientation[0].axResolution && Orientation[1].axResolution) {
 
664
                                        m_maxAzimuth = Orientation[0].axMax;
 
665
                                        m_maxAltitude = Orientation[1].axMax;
 
666
                                }
 
667
                                else {  /* no so dont do tilt stuff */
 
668
                                        m_maxAzimuth = m_maxAltitude = 0;
 
669
                                }
 
670
                        }
 
671
 
 
672
                        m_tabletData->Active = 0;
 
673
                }
 
674
        }
 
675
}
 
676
 
 
677
void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
 
678
{
 
679
        PACKET pkt;
 
680
        if (m_wintab) {
 
681
                GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" );
 
682
                if (fpWTPacket) {
 
683
                        if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {
 
684
                                if (m_tabletData) {
 
685
                                        switch (pkt.pkCursor) {
 
686
                                                case 0: /* first device */
 
687
                                                case 3: /* second device */
 
688
                                                        m_tabletData->Active = 0; /* puck - not yet supported */
 
689
                                                        break;
 
690
                                                case 1:
 
691
                                                case 4:
 
692
                                                        m_tabletData->Active = 1; /* stylus */
 
693
                                                        break;
 
694
                                                case 2:
 
695
                                                case 5:
 
696
                                                        m_tabletData->Active = 2; /* eraser */
 
697
                                                        break;
 
698
                                        }
 
699
                                        if (m_maxPressure > 0) {
 
700
                                                m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
 
701
                                        } else {
 
702
                                                m_tabletData->Pressure = 1.0f;
 
703
                                        }
 
704
 
 
705
                                        if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
 
706
                                                ORIENTATION ort = pkt.pkOrientation;
 
707
                                                float vecLen;
 
708
                                                float altRad, azmRad;   /* in radians */
 
709
 
 
710
                                                /*
 
711
                                                from the wintab spec:
 
712
                                                orAzimuth       Specifies the clockwise rotation of the
 
713
                                                cursor about the z axis through a full circular range.
 
714
 
 
715
                                                orAltitude      Specifies the angle with the x-y plane
 
716
                                                through a signed, semicircular range.  Positive values
 
717
                                                specify an angle upward toward the positive z axis;
 
718
                                                negative values specify an angle downward toward the negative z axis.
 
719
 
 
720
                                                wintab.h defines .orAltitude as a UINT but documents .orAltitude
 
721
                                                as positive for upward angles and negative for downward angles.
 
722
                                                WACOM uses negative altitude values to show that the pen is inverted;
 
723
                                                therefore we cast .orAltitude as an (int) and then use the absolute value.
 
724
                                                */
 
725
                                                
 
726
                                                /* convert raw fixed point data to radians */
 
727
                                                altRad = (fabs((float)ort.orAltitude)/(float)m_maxAltitude) * M_PI/2.0;
 
728
                                                azmRad = ((float)ort.orAzimuth/(float)m_maxAzimuth) * M_PI*2.0;
 
729
 
 
730
                                                /* find length of the stylus' projected vector on the XY plane */
 
731
                                                vecLen = cos(altRad);
 
732
 
 
733
                                                /* from there calculate X and Y components based on azimuth */
 
734
                                                m_tabletData->Xtilt = sin(azmRad) * vecLen;
 
735
                                                m_tabletData->Ytilt = sin(M_PI/2.0 - azmRad) * vecLen;
 
736
 
 
737
                                        } else {
 
738
                                                m_tabletData->Xtilt = 0.0f;
 
739
                                                m_tabletData->Ytilt = 0.0f;
 
740
                                        }
 
741
                                }
 
742
                        }
 
743
                }
 
744
        }
 
745
}
 
746
 
 
747
/** Reverse the bits in a GHOST_TUns8 */
 
748
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
 
749
{
 
750
        ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
 
751
        ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
 
752
        ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
 
753
        return ch;
 
754
}
 
755
 
 
756
/** Reverse the bits in a GHOST_TUns16 */
 
757
static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
 
758
{
 
759
        shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
 
760
        shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
 
761
        shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
 
762
        shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
 
763
        return shrt;
 
764
}
 
765
GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 
 
766
                                        GHOST_TUns8 mask[16][2], int hotX, int hotY)
 
767
{
 
768
        return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, 
 
769
                                                                        16, 16, hotX, hotY, 0, 1);
 
770
}
 
771
 
 
772
GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, 
 
773
                                        GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY, 
 
774
                                        int fg_color, int bg_color)
 
775
{
 
776
        GHOST_TUns32 andData[32];
 
777
        GHOST_TUns32 xorData[32];
 
778
        GHOST_TUns32 fullBitRow, fullMaskRow;
 
779
        int x, y, cols;
 
780
        
 
781
        cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */
 
782
        if (sizeX%8) cols++;
 
783
        
 
784
        if (m_customCursor) {
 
785
                DestroyCursor(m_customCursor);
 
786
                m_customCursor = NULL;
 
787
        }
 
788
 
 
789
        memset(&andData, 0xFF, sizeof(andData));
 
790
        memset(&xorData, 0, sizeof(xorData));
 
791
 
 
792
        for (y=0; y<sizeY; y++) {
 
793
                fullBitRow=0;
 
794
                fullMaskRow=0;
 
795
                for (x=cols-1; x>=0; x--){
 
796
                        fullBitRow<<=8;
 
797
                        fullMaskRow<<=8;
 
798
                        fullBitRow  |= uns8ReverseBits(bitmap[cols*y + x]);
 
799
                        fullMaskRow |= uns8ReverseBits(  mask[cols*y + x]);
 
800
                }
 
801
                xorData[y]= fullBitRow & fullMaskRow;
 
802
                andData[y]= ~fullMaskRow;
 
803
        }
 
804
 
 
805
        m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
 
806
        if (!m_customCursor) {
 
807
                return GHOST_kFailure;
 
808
        }
 
809
 
 
810
        if (::GetForegroundWindow() == m_hWnd) {
 
811
                loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
 
812
        }
 
813
 
 
814
        return GHOST_kSuccess;
 
815
}
 
816
 
 
817
 
 
818
/*  Ron Fosner's code for weighting pixel formats and forcing software.
 
819
        See http://www.opengl.org/resources/faq/technical/weight.cpp */
 
820
 
 
821
static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) {
 
822
        int weight = 0;
 
823
        
 
824
        /* assume desktop color depth is 32 bits per pixel */
 
825
        
 
826
        /* cull unusable pixel formats */
 
827
        /* if no formats can be found, can we determine why it was rejected? */
 
828
        if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) ||
 
829
                !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
 
830
                !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
 
831
                ( pfd.cDepthBits <= 8 ) ||
 
832
                !(pfd.iPixelType == PFD_TYPE_RGBA) )
 
833
                return 0;
 
834
        
 
835
        weight = 1;  /* it's usable */
 
836
        
 
837
        /* the bigger the depth buffer the better */
 
838
        /* give no weight to a 16-bit depth buffer, because those are crap */
 
839
        weight += pfd.cDepthBits - 16;
 
840
        
 
841
        weight += pfd.cColorBits - 8;
 
842
        
 
843
        /* want swap copy capability -- it matters a lot */
 
844
        if(pfd.dwFlags & PFD_SWAP_COPY) weight += 16;
 
845
        
 
846
        /* but if it's a generic (not accelerated) view, it's really bad */
 
847
        if(pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10;
 
848
        
 
849
        return weight;
 
850
}
 
851
 
 
852
/* A modification of Ron Fosner's replacement for ChoosePixelFormat */ 
 
853
/* returns 0 on error, else returns the pixel format number to be used */
 
854
static int EnumPixelFormats(HDC hdc) {
 
855
        int iPixelFormat;
 
856
        int i, n, w, weight = 0;
 
857
        PIXELFORMATDESCRIPTOR pfd, pfd_fallback;
 
858
        
 
859
        /* we need a device context to do anything */
 
860
        if(!hdc) return 0;
 
861
 
 
862
        iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */
 
863
        
 
864
        /* obtain detailed information about 
 
865
        the device context's first pixel format */
 
866
        n = 1+::DescribePixelFormat(hdc, iPixelFormat, 
 
867
                sizeof(PIXELFORMATDESCRIPTOR), &pfd);
 
868
        
 
869
        /* choose a pixel format using the useless Windows function in case
 
870
                we come up empty handed */
 
871
        iPixelFormat = ::ChoosePixelFormat( hdc, &sPreferredFormat );
 
872
        
 
873
        if(!iPixelFormat) return 0; /* couldn't find one to use */
 
874
 
 
875
        for(i=1; i<=n; i++) { /* not the idiom, but it's right */
 
876
                ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
 
877
                w = WeightPixelFormat(pfd);
 
878
                // be strict on stereo
 
879
                if (!((sPreferredFormat.dwFlags ^ pfd.dwFlags) & PFD_STEREO))   {
 
880
                        if(w > weight) {
 
881
                                weight = w;
 
882
                                iPixelFormat = i;
 
883
                        }
 
884
                }
 
885
        }
 
886
        if (weight == 0) {
 
887
                // we could find the correct stereo setting, just find any suitable format 
 
888
                for(i=1; i<=n; i++) { /* not the idiom, but it's right */
 
889
                        ::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
 
890
                        w = WeightPixelFormat(pfd);
 
891
                        if(w > weight) {
 
892
                                weight = w;
 
893
                                iPixelFormat = i;
 
894
                        }
 
895
                }
 
896
        }
 
897
        return iPixelFormat;
 
898
}
 
899
 
 
900