vtkWin32OpenGLRenderWindow.cxx 47.1 KB
Newer Older
1
2
/*=========================================================================

3
4
Program:   Visualization Toolkit
Module:    vtkWin32OpenGLRenderWindow.cxx
5

6
7
8
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
Will Schroeder's avatar
Will Schroeder committed
9

10
11
12
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notice for more information.
13
14

=========================================================================*/
Will Schroeder's avatar
Will Schroeder committed
15
#include "vtkWin32OpenGLRenderWindow.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
16

Andy Cedilnik's avatar
Andy Cedilnik committed
17
#include "vtkIdList.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
18
#include "vtkCommand.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
19
#include "vtkObjectFactory.h"
Will Schroeder's avatar
Will Schroeder committed
20
#include "vtkOpenGLActor.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
21
#include "vtkOpenGLCamera.h"
Will Schroeder's avatar
Will Schroeder committed
22
#include "vtkOpenGLLight.h"
Will Schroeder's avatar
Will Schroeder committed
23
#include "vtkOpenGLPolyDataMapper.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
24
25
26
#include "vtkOpenGLProperty.h"
#include "vtkOpenGLRenderer.h"
#include "vtkOpenGLTexture.h"
Burlen Loring's avatar
Burlen Loring committed
27
28
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLError.h"
Andy Cedilnik's avatar
Andy Cedilnik committed
29
30
31
32
#include "vtkRendererCollection.h"
#include "vtkWin32RenderWindowInteractor.h"

#include <math.h>
33
#include <vtksys/ios/sstream>
34

35
#include "vtkOpenGL.h"
Burlen Loring's avatar
Burlen Loring committed
36
#include "vtkOpenGLError.h"
37
#include "vtkgl.h"
38

Brad King's avatar
Brad King committed
39
vtkStandardNewMacro(vtkWin32OpenGLRenderWindow);
40

Jim Miller's avatar
Style:    
Jim Miller committed
41
#define VTK_MAX_LIGHTS 8
42

Will Schroeder's avatar
Will Schroeder committed
43
vtkWin32OpenGLRenderWindow::vtkWin32OpenGLRenderWindow()
44
{
Berk Geveci's avatar
Berk Geveci committed
45
  this->ApplicationInstance =  NULL;
LYMB Demo's avatar
LYMB Demo committed
46
  this->Palette = NULL;
47
48
49
  this->ContextId = 0;
  this->MultiSamples = 8;
  this->WindowId = 0;
LYMB Demo's avatar
LYMB Demo committed
50
  this->ParentId = 0;
51
  this->NextWindowId = 0;
52
53
  this->DeviceContext = (HDC)0;         // hsr
  this->MFChandledWindow = FALSE;       // hsr
Mathieu Malaterre's avatar
Mathieu Malaterre committed
54
  this->StereoType = VTK_STEREO_CRYSTAL_EYES;
55
  this->CursorHidden = 0;
56
  this->Capabilities = 0;
57
58
59

  this->ScreenDeviceContext = (HDC)0;
  this->MemoryHdc = (HDC)0;
Mathieu Malaterre's avatar
Mathieu Malaterre committed
60
61
  this->CreatingOffScreenWindow = 0;
  this->WindowIdReferenceCount = 0;
Yuanxin Liu's avatar
Yuanxin Liu committed
62
63
64
65
66
67
68

  this->ScreenMapped = this->Mapped;
  this->ScreenWindowSize[0] = this->Size[0];
  this->ScreenWindowSize[1] = this->Size[1];
  this->ScreenDeviceContext = this->DeviceContext;
  this->ScreenDoubleBuffer = this->DoubleBuffer;
  this->ScreenContextId = this->ContextId;
69
70
}

LYMB Demo's avatar
LYMB Demo committed
71
72
vtkWin32OpenGLRenderWindow::~vtkWin32OpenGLRenderWindow()
{
73
  this->Finalize();
74

75
  vtkRenderer *ren;
76
77
78
  vtkCollectionSimpleIterator rit;
  this->Renderers->InitTraversal(rit);
  while ( (ren = this->Renderers->GetNextRenderer(rit)) )
79
80
81
82
    {
    ren->SetRenderWindow(NULL);
    }

83
  delete[] this->Capabilities;
LYMB Demo's avatar
LYMB Demo committed
84
85
}

86
87
void vtkWin32OpenGLRenderWindow::Clean()
{
Jim Miller's avatar
Jim Miller committed
88
  GLuint id;
89

90
  /* finish OpenGL rendering */
91
  if (this->OwnContext && this->ContextId)
92
    {
Ken Martin's avatar
Ken Martin committed
93
    this->MakeCurrent();
Burlen Loring's avatar
Burlen Loring committed
94
    vtkOpenGLClearErrorMacro();
95

96
     /* first delete all the old lights */
97
98
99
100
    for (short cur_light = GL_LIGHT0; cur_light < GL_LIGHT0+VTK_MAX_LIGHTS; cur_light++)
      {
      glDisable((GLenum)cur_light);
      }
101

Ken Martin's avatar
Ken Martin committed
102
103
104
105
106
107
108
    /* now delete all textures */
    glDisable(GL_TEXTURE_2D);
    for (int i = 1; i < this->TextureResourceIds->GetNumberOfIds(); i++)
      {
      id = (GLuint) this->TextureResourceIds->GetId(i);
#ifdef GL_VERSION_1_1
      if (glIsTexture(id))
109
        {
Ken Martin's avatar
Ken Martin committed
110
        glDeleteTextures(1, &id);
111
        }
Ken Martin's avatar
Ken Martin committed
112
113
#else
      if (glIsList(id))
114
        {
Ken Martin's avatar
Ken Martin committed
115
        glDeleteLists(id,1);
116
        }
Ken Martin's avatar
Ken Martin committed
117
118
#endif
      }
Burlen Loring's avatar
Burlen Loring committed
119
    vtkOpenGLCheckErrorMacro("failed in Clean");
120
121

    this->CleanUpRenderers();
122

123
124
125
126
    // Note: wglMakeCurrent(NULL,NULL) is valid according to the documentation
    // and works with nVidia and ATI but not with Intel. Passing an existing
    // device context works in any case.
    // see VTK Bug 7119.
127
    if(wglMakeCurrent(this->DeviceContext,NULL)!=TRUE)
Ken Martin's avatar
Ken Martin committed
128
129
130
      {
      vtkErrorMacro("wglMakeCurrent failed in Clean(), error: " << GetLastError());
      }
131
    if (wglDeleteContext(this->ContextId) != TRUE)
Ken Martin's avatar
Ken Martin committed
132
133
134
      {
      vtkErrorMacro("wglDeleteContext failed in Clean(), error: " << GetLastError());
      }
135
    }
136
137
  this->ContextId = NULL;

138
139
  if (this->Palette)
    {
Ken Martin's avatar
Ken Martin committed
140
141
142
    SelectPalette(this->DeviceContext, this->OldPalette, FALSE); // SVA delete the old palette
    DeleteObject(this->Palette);
    this->Palette = NULL;
143
144
145
    }
}

146
147
148
149
150
151
152
void vtkWin32OpenGLRenderWindow::CleanUpRenderers()
{
  // tell each of the renderers that this render window/graphics context
  // is being removed (the RendererCollection is removed by vtkRenderWindow's
  // destructor)
  vtkRenderer *ren;
  vtkCollectionSimpleIterator rsit;
153
  for (this->Renderers->InitTraversal(rsit);
154
155
156
157
158
159
       (ren = this->Renderers->GetNextRenderer(rsit));)
    {
    ren->SetRenderWindow(NULL);
    }
}

160
161
LRESULT APIENTRY vtkWin32OpenGLRenderWindow::WndProc(HWND hWnd, UINT message,
                                                     WPARAM wParam,
162
                                                     LPARAM lParam)
163
{
164
165
  LRESULT res;

166
  vtkWin32OpenGLRenderWindow *me =
167
    (vtkWin32OpenGLRenderWindow *)vtkGetWindowLong(hWnd,sizeof(vtkLONG));
168

169
170
171
172
173
174
175
  if (me && me->GetReferenceCount()>0)
    {
    me->Register(me);
    res = me->MessageProc(hWnd, message, wParam, lParam);
    me->UnRegister(me);
    }
  else
Jim Miller's avatar
Style:    
Jim Miller committed
176
    {
177
    res = DefWindowProc(hWnd, message, wParam, lParam);
Jim Miller's avatar
Style:    
Jim Miller committed
178
    }
179

180
  return res;
181
182
}

183
void vtkWin32OpenGLRenderWindow::SetWindowName( const char * _arg )
Ken Martin's avatar
Ken Martin committed
184
{
LYMB Demo's avatar
LYMB Demo committed
185
  vtkWindow::SetWindowName(_arg);
Jim Miller's avatar
Style:    
Jim Miller committed
186
187
  if (this->WindowId)
    {
188
#ifdef UNICODE
189
190
191
192
    wchar_t *wname = new wchar_t [mbstowcs(NULL, this->WindowName, 32000)+1];
    mbstowcs(wname, this->WindowName, 32000);
    SetWindowText(this->WindowId, wname);
    delete [] wname;
193
#else
194
    SetWindowText(this->WindowId, this->WindowName);
195
#endif
Jim Miller's avatar
Style:    
Jim Miller committed
196
    }
Ken Martin's avatar
Ken Martin committed
197
198
}

Will Schroeder's avatar
Will Schroeder committed
199
int vtkWin32OpenGLRenderWindow::GetEventPending()
LYMB Demo's avatar
LYMB Demo committed
200
201
{
  MSG msg;
Will Schroeder's avatar
Will Schroeder committed
202
203
  if (PeekMessage(&msg,this->WindowId,WM_MOUSEFIRST,WM_MOUSELAST,PM_NOREMOVE))
    {
204
    if (msg.message == WM_MOUSEMOVE)
Will Schroeder's avatar
Will Schroeder committed
205
      {
206
      PeekMessage(&msg,this->WindowId,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE);
Will Schroeder's avatar
Will Schroeder committed
207
      }
208
209
210
211
    if ((msg.message == WM_LBUTTONDOWN) ||
        (msg.message == WM_RBUTTONDOWN) ||
        (msg.message == WM_MBUTTONDOWN))
      {
Will Schroeder's avatar
Will Schroeder committed
212
      return 1;
213
      }
214
    }
215

216
  return 0;
LYMB Demo's avatar
LYMB Demo committed
217
218
}

219
220
221
222
223
224
225
226
227
228
// ----------------------------------------------------------------------------
bool vtkWin32OpenGLRenderWindow::InitializeFromCurrentContext()
{
  HGLRC currentContext = wglGetCurrentContext();
  if (currentContext != NULL)
    {
    this->SetWindowId(WindowFromDC(wglGetCurrentDC()));
    this->SetDeviceContext(wglGetCurrentDC());
    this->SetContextId(currentContext);
    this->OpenGLInit();
229
    this->OwnContext = 0;
230
231
232
233
234
    return true;
    }
  return false;
}

235
// ----------------------------------------------------------------------------
Will Schroeder's avatar
Will Schroeder committed
236
void vtkWin32OpenGLRenderWindow::MakeCurrent()
237
{
Ken Martin's avatar
Ken Martin committed
238
  // Try to avoid doing anything (for performance).
Ken Martin's avatar
Ken Martin committed
239
240
241
242
  HGLRC current = wglGetCurrentContext();
  if (this->ContextId != current)
    {
    if(this->IsPicking && current)
Ken Martin's avatar
Ken Martin committed
243
      {
Bill Hoffman's avatar
Bill Hoffman committed
244
245
246
247
      vtkErrorMacro("Attempting to call MakeCurrent for a different window"
                    " than the one doing the picking, this can causes crashes"
                    " and/or bad pick results");
      }
248
    else
Bill Hoffman's avatar
Bill Hoffman committed
249
      {
250
      if (wglMakeCurrent(this->DeviceContext, this->ContextId) != TRUE)
Bill Hoffman's avatar
Bill Hoffman committed
251
252
        {
        LPVOID lpMsgBuf;
253
254
255
        ::FormatMessage(
          FORMAT_MESSAGE_ALLOCATE_BUFFER |
          FORMAT_MESSAGE_FROM_SYSTEM |
Bill Hoffman's avatar
Bill Hoffman committed
256
257
258
259
260
261
          FORMAT_MESSAGE_IGNORE_INSERTS,
          NULL,
          GetLastError(),
          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
          (LPTSTR) &lpMsgBuf,
          0,
262
          NULL
Bill Hoffman's avatar
Bill Hoffman committed
263
          );
264
265
        if(lpMsgBuf)
          {
266
#ifdef UNICODE
267
268
269
270
271
272
273
          wchar_t *wmsg = new wchar_t [mbstowcs(NULL, (const char*)lpMsgBuf, 32000)+1];
          wchar_t *wtemp = new wchar_t [mbstowcs(NULL, "wglMakeCurrent failed in MakeCurrent(), error: ", 32000)+1];
          mbstowcs(wmsg, (const char*)lpMsgBuf, 32000);
          mbstowcs(wtemp, "wglMakeCurrent failed in MakeCurrent(), error: ", 32000);
          vtkErrorMacro(<< wcscat(wtemp, wmsg));
          delete [] wmsg;
          delete [] wtemp;
274
#else
275
          vtkErrorMacro("wglMakeCurrent failed in MakeCurrent(), error: "
276
                        << (LPCTSTR)lpMsgBuf);
277
#endif
278
279
          ::LocalFree( lpMsgBuf );
          }
Bill Hoffman's avatar
Bill Hoffman committed
280
        }
Ken Martin's avatar
Ken Martin committed
281
      }
282
    }
283
284
}

285
286
287
288
289
// ----------------------------------------------------------------------------
// Description:
// Tells if this window is the current OpenGL context for the calling thread.
bool vtkWin32OpenGLRenderWindow::IsCurrent()
{
290
  return this->ContextId!=0 && this->ContextId==wglGetCurrentContext();
291
}
292

293
// ----------------------------------------------------------------------------
Will Schroeder's avatar
Will Schroeder committed
294
void vtkWin32OpenGLRenderWindow::SetSize(int x, int y)
LYMB Demo's avatar
LYMB Demo committed
295
296
297
298
{
  static int resizing = 0;
  if ((this->Size[0] != x) || (this->Size[1] != y))
    {
Ken Martin's avatar
Ken Martin committed
299
300
301
    this->Modified();
    this->Size[0] = x;
    this->Size[1] = y;
302
303
304
305
306
307

    if (this->Interactor)
      {
      this->Interactor->SetSize(x, y);
      }

Ken Martin's avatar
Ken Martin committed
308
309
    if (this->OffScreenRendering)
      {
310
      if(!this->CreatingOffScreenWindow)
311
        {
312
313
314
315
316
317
318
        if (!resizing)
          {
          resizing = 1;
          this->CleanUpOffScreenRendering();
          this->CreateOffScreenWindow(x,y);
          resizing = 0;
          }
319
        }
Ken Martin's avatar
Ken Martin committed
320
      }
321

Ken Martin's avatar
Ken Martin committed
322
323
324
    else if (this->Mapped)
      {
      if (!resizing)
LYMB Demo's avatar
LYMB Demo committed
325
        {
Ken Martin's avatar
Ken Martin committed
326
        resizing = 1;
327

Ken Martin's avatar
Ken Martin committed
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
        if (this->ParentId)
          {
          SetWindowExtEx(this->DeviceContext,x,y,NULL);
          SetViewportExtEx(this->DeviceContext,x,y,NULL);
          SetWindowPos(this->WindowId,HWND_TOP,0,0,
                       x, y, SWP_NOMOVE | SWP_NOZORDER);
          }
        else
          {
          SetWindowPos(this->WindowId,HWND_TOP,0,0,
                       x+2*GetSystemMetrics(SM_CXFRAME),
                       y+2*GetSystemMetrics(SM_CYFRAME) +GetSystemMetrics(SM_CYCAPTION),
                       SWP_NOMOVE | SWP_NOZORDER);
          }
        resizing = 0;
LYMB Demo's avatar
LYMB Demo committed
343
        }
Ken Martin's avatar
Ken Martin committed
344
      }
LYMB Demo's avatar
LYMB Demo committed
345
346
    }
}
LYMB Demo's avatar
LYMB Demo committed
347

Will Schroeder's avatar
Will Schroeder committed
348
void vtkWin32OpenGLRenderWindow::SetPosition(int x, int y)
LYMB Demo's avatar
LYMB Demo committed
349
350
351
352
353
{
  static int resizing = 0;

  if ((this->Position[0] != x) || (this->Position[1] != y))
    {
Ken Martin's avatar
Ken Martin committed
354
355
356
357
358
359
    this->Modified();
    this->Position[0] = x;
    this->Position[1] = y;
    if (this->Mapped)
      {
      if (!resizing)
LYMB Demo's avatar
LYMB Demo committed
360
        {
Ken Martin's avatar
Ken Martin committed
361
        resizing = 1;
362

Ken Martin's avatar
Ken Martin committed
363
364
365
        SetWindowPos(this->WindowId,HWND_TOP,x,y,
                     0, 0, SWP_NOSIZE | SWP_NOZORDER);
        resizing = 0;
LYMB Demo's avatar
LYMB Demo committed
366
        }
Ken Martin's avatar
Ken Martin committed
367
      }
LYMB Demo's avatar
LYMB Demo committed
368
369
370
    }
}

371
372

// End the rendering process and display the image.
Will Schroeder's avatar
Will Schroeder committed
373
void vtkWin32OpenGLRenderWindow::Frame(void)
374
{
375
  this->MakeCurrent();
376
  if (!this->AbortRender && this->DoubleBuffer && this->SwapBuffers)
377
    {
378
379
380
381
382
383
384
385
    // If this check is not enforced, we crash in offscreen rendering
    if (this->DeviceContext)
      {
      // use global scope to get Win32 API SwapBuffers and not be
      // confused with this->SwapBuffers
      ::SwapBuffers(this->DeviceContext);
      vtkDebugMacro(<< " SwapBuffers\n");
      }
386
    }
Ken Martin's avatar
Ken Martin committed
387
  else
388
    {
Ken Martin's avatar
Ken Martin committed
389
    glFlush();
390
    }
391
}
392
393
394
395
396
397

int vtkWin32OpenGLRenderWindow::SupportsOpenGL()
{
  MakeCurrent();
  if (!this->DeviceContext)
    {
398
    return 0;
399
400
401
402
403
    }

  int pixelFormat = GetPixelFormat(this->DeviceContext);
  PIXELFORMATDESCRIPTOR pfd;

404
405
  DescribePixelFormat(this->DeviceContext, pixelFormat,
                      sizeof(PIXELFORMATDESCRIPTOR), &pfd);
406
407
408
409
410
411
412
413
414
415
416
417

  return (pfd.dwFlags & PFD_SUPPORT_OPENGL) ? 1:0;

}


int vtkWin32OpenGLRenderWindow::IsDirect()
{

  MakeCurrent();
  if (!this->DeviceContext)
    {
Mathieu Malaterre's avatar
Mathieu Malaterre committed
418
    return 0;
419
420
421
422
423
    }

  int pixelFormat = GetPixelFormat(this->DeviceContext);
  PIXELFORMATDESCRIPTOR pfd;

424
425
  DescribePixelFormat(this->DeviceContext, pixelFormat,
                      sizeof(PIXELFORMATDESCRIPTOR), &pfd);
426
427
428
429
430
431
432
433
434
435
436
437

  return (pfd.dwFlags & PFD_GENERIC_FORMAT) ? 0:1;

}


const char* vtkWin32OpenGLRenderWindow::ReportCapabilities()
{
  MakeCurrent();

  if (!this->DeviceContext)
    {
438
    return "no device context";
439
440
441
442
443
    }

  int pixelFormat = GetPixelFormat(this->DeviceContext);
  PIXELFORMATDESCRIPTOR pfd;

444
445
  DescribePixelFormat(this->DeviceContext, pixelFormat,
                      sizeof(PIXELFORMATDESCRIPTOR), &pfd);
446

447
448
449
450
451
  const char *glVendor = (const char *) glGetString(GL_VENDOR);
  const char *glRenderer = (const char *) glGetString(GL_RENDERER);
  const char *glVersion = (const char *) glGetString(GL_VERSION);
  const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);

452
  vtksys_ios::ostringstream strm;
453
454
455
456
457
  strm << "OpenGL vendor string:  " << glVendor << endl;
  strm << "OpenGL renderer string:  " << glRenderer << endl;
  strm << "OpenGL version string:  " << glVersion << endl;
  strm << "OpenGL extensions:  " << glExtensions << endl;
  strm << "PixelFormat Descriptor:" << endl;
Jeff Lee's avatar
Jeff Lee committed
458
  strm << "depth:  " << static_cast<int>(pfd.cDepthBits) << endl;
459
460
  if (pfd.cColorBits <= 8)
    {
461
    strm << "class:  PseudoColor" << endl;
462
    }
463
464
  else
    {
465
    strm << "class:  TrueColor" << endl;
466
    }
Jeff Lee's avatar
Jeff Lee committed
467
468
  strm << "buffer size:  " << static_cast<int>(pfd.cColorBits) << endl;
  strm << "level:  " << static_cast<int>(pfd.bReserved) << endl;
469
470
471
472
473
474
475
476
  if (pfd.iPixelType == PFD_TYPE_RGBA)
    {
    strm << "renderType:  rgba" << endl;
    }
  else
    {
    strm <<"renderType:  ci" << endl;
    }
Jeff Lee's avatar
Jeff Lee committed
477
  if (pfd.dwFlags & PFD_DOUBLEBUFFER) {
478
  strm << "double buffer:  True" << endl;
Jeff Lee's avatar
Jeff Lee committed
479
  } else {
480
  strm << "double buffer:  False" << endl;
Jeff Lee's avatar
Jeff Lee committed
481
482
  }
  if (pfd.dwFlags & PFD_STEREO) {
483
  strm << "stereo:  True" << endl;
Jeff Lee's avatar
Jeff Lee committed
484
  } else {
485
  strm << "stereo:  False" << endl;
Jeff Lee's avatar
Jeff Lee committed
486
487
  }
  if (pfd.dwFlags & PFD_GENERIC_FORMAT) {
488
  strm << "hardware acceleration:  False" << endl;
Jeff Lee's avatar
Jeff Lee committed
489
  } else {
490
  strm << "hardware acceleration:  True" << endl;
Jeff Lee's avatar
Jeff Lee committed
491
  }
Jeff Lee's avatar
Jeff Lee committed
492
493
494
495
496
  strm << "rgba:  redSize=" << static_cast<int>(pfd.cRedBits) << " greenSize=" << static_cast<int>(pfd.cGreenBits) << "blueSize=" << static_cast<int>(pfd.cBlueBits) << "alphaSize=" << static_cast<int>(pfd.cAlphaBits) << endl;
  strm << "aux buffers:  " << static_cast<int>(pfd.cAuxBuffers)<< endl;
  strm << "depth size:  " << static_cast<int>(pfd.cDepthBits) << endl;
  strm << "stencil size:  " << static_cast<int>(pfd.cStencilBits) << endl;
  strm << "accum:  redSize=" << static_cast<int>(pfd.cAccumRedBits) << " greenSize=" << static_cast<int>(pfd.cAccumGreenBits) << "blueSize=" << static_cast<int>(pfd.cAccumBlueBits) << "alphaSize=" << static_cast<int>(pfd.cAccumAlphaBits) << endl;
497

498
  delete[] this->Capabilities;
499

500
501
  size_t len = strm.str().length() + 1;
  this->Capabilities = new char[len];
502
  strncpy(this->Capabilities, strm.str().c_str(), len);
503

504
  return this->Capabilities;
505
506
}

507
typedef bool (APIENTRY *wglChoosePixelFormatARBType)(HDC, const int*, const float*, unsigned int, int*, unsigned int*);
508

509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
bool WGLisExtensionSupported(const char *extension)
{
  const size_t extlen = strlen(extension);
  const char *supported = NULL;

  // Try To Use wglGetExtensionStringARB On Current DC, If Possible
  PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");

  if (wglGetExtString)
    {
    supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC());
    }

  // If That Failed, Try Standard Opengl Extensions String
  if (supported == NULL)
    {
    supported = (char*)glGetString(GL_EXTENSIONS);
    }

  // If That Failed Too, Must Be No Extensions Supported
  if (supported == NULL)
    {
    return false;
    }

  // Begin Examination At Start Of String, Increment By 1 On False Match
  for (const char* p = supported; ; p++)
    {
    // Advance p Up To The Next Possible Match
    p = strstr(p, extension);

    if (p == NULL)
      {
      return false; // No Match
      }

    // Make Sure That Match Is At The Start Of The String Or That
    // The Previous Char Is A Space, Or Else We Could Accidentally
    // Match "wglFunkywglExtension" With "wglExtension"

    // Also, Make Sure That The Following Character Is Space Or NULL
    // Or Else "wglExtensionTwo" Might Match "wglExtension"
    if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
      {
      return true; // Match
      }
    }
}

558
559
void vtkWin32OpenGLRenderWindow::SetupPixelFormat(HDC hDC, DWORD dwFlags,
                                                  int debug, int bpp,
560
                                                  int zbpp)
LYMB Demo's avatar
LYMB Demo committed
561
{
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
  // Create a dummy window, needed for calling wglGetProcAddress.
#ifdef UNICODE
  HWND tempId = CreateWindow(L"vtkOpenGL", 0, 0, 0, 0, 1, 1, 0, 0, this->ApplicationInstance, 0);
#else
  HWND tempId = CreateWindow("vtkOpenGL", 0, 0, 0, 0, 1, 1, 0, 0, this->ApplicationInstance, 0);
#endif
  HDC tempDC = GetDC(tempId);
  PIXELFORMATDESCRIPTOR tempPfd;
  memset(&tempPfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
  tempPfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  tempPfd.nVersion = 1;
  tempPfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
  tempPfd.iPixelType = PFD_TYPE_RGBA;
  int tempPixelFormat = ChoosePixelFormat(tempDC, &tempPfd);
  SetPixelFormat(tempDC, tempPixelFormat, &tempPfd);
  HGLRC tempContext = wglCreateContext(tempDC);
  wglMakeCurrent(tempDC, tempContext);

  // First we try to use the newer wglChoosePixelFormatARB which enables
  // features like multisamples.
  int pixelFormat = 0;
  wglChoosePixelFormatARBType wglChoosePixelFormatARB =
    reinterpret_cast<wglChoosePixelFormatARBType>(wglGetProcAddress("wglChoosePixelFormatARB"));
  if ((dwFlags & PFD_DRAW_TO_WINDOW) && wglChoosePixelFormatARB)
    {
    int attrib[] = {
      vtkwgl::ACCELERATION_ARB, vtkwgl::FULL_ACCELERATION_ARB,
      vtkwgl::SUPPORT_OPENGL_ARB, TRUE,
      vtkwgl::DRAW_TO_WINDOW_ARB, TRUE,
      vtkwgl::DOUBLE_BUFFER_ARB, TRUE,
      vtkwgl::COLOR_BITS_ARB, bpp/4*3,
      vtkwgl::DEPTH_BITS_ARB, zbpp/4*3,
      vtkwgl::PIXEL_TYPE_ARB, vtkwgl::TYPE_RGBA_ARB,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    unsigned int n = 14;
    if (this->AlphaBitPlanes)
      {
      attrib[n] = vtkwgl::ALPHA_BITS_ARB;
      attrib[n+1] = bpp/4;
      n += 2;
      }
    if (this->StencilCapable)
      {
      attrib[n] = vtkwgl::STENCIL_BITS_ARB;
      attrib[n+1] = 8;
      n += 2;
      }
    if (dwFlags & PFD_STEREO)
      {
      attrib[n] = vtkwgl::STEREO_ARB;
      attrib[n+1] = TRUE;
      n += 2;
      }
    unsigned int multiSampleAttributeIndex = 0;
    if (this->MultiSamples > 1 && WGLisExtensionSupported("WGL_ARB_multisample"))
      {
      attrib[n] = vtkwgl::SAMPLE_BUFFERS_ARB;
      attrib[n+1] = 1;
      attrib[n+2] = vtkwgl::SAMPLES_ARB;
      attrib[n+3] = this->MultiSamples;
      multiSampleAttributeIndex = n+3;
      n += 4;
      }
    unsigned int numFormats;
    if (!wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats))
      {
      // If the requested number of multisamples does not work, try
      // scaling down the number of multisamples a few times.
      if (multiSampleAttributeIndex)
        {
        attrib[multiSampleAttributeIndex] /= 2;
        if (!wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats))
          {
          attrib[multiSampleAttributeIndex] /= 2;
          wglChoosePixelFormatARB(hDC, attrib, 0, 1, &pixelFormat, &numFormats);
          }
        }
      }
    PIXELFORMATDESCRIPTOR pfd;
    DescribePixelFormat(hDC, pixelFormat, sizeof(pfd), &pfd);
    if (!SetPixelFormat(hDC, pixelFormat, &pfd))
      {
      pixelFormat = 0;
      }
    }

  // Delete the dummy window
  wglMakeCurrent(tempDC, 0);
  wglDeleteContext(tempContext);
  ReleaseDC(tempId, tempDC);
Burlen Loring's avatar
Burlen Loring committed
652
  ::DestroyWindow(tempId); // windows api
653
654
655
656
657
658
659
660

  // If we got a valid pixel format in the process, we are done.
  // Otherwise, we use the old approach of using ChoosePixelFormat.
  if (pixelFormat)
    {
    return;
    }

661
662
663
664
665
  PIXELFORMATDESCRIPTOR pfd = {
    sizeof(PIXELFORMATDESCRIPTOR),  /* size */
    1,                              /* version */
    dwFlags         ,               /* support double-buffering */
    PFD_TYPE_RGBA,                  /* color type */
Kyle Lutz's avatar
Kyle Lutz committed
666
    bpp,                             /* preferred color depth */
667
    0, 0, 0, 0, 0, 0,               /* color bits (ignored) */
668
    this->AlphaBitPlanes ? bpp/4 : 0, /* no alpha buffer */
669
670
671
672
    0,                              /* alpha bits (ignored) */
    0,                              /* no accumulation buffer */
    0, 0, 0, 0,                     /* accum bits (ignored) */
    zbpp,                           /* depth buffer */
673
    this->StencilCapable,           /* stencil buffer */
674
675
676
677
678
679
680
681
682
683
684
    0,                              /* no auxiliary buffers */
    PFD_MAIN_PLANE,                 /* main layer */
    0,                              /* reserved */
    0, 0, 0,                        /* no layer, visible, damage masks */
  };
  // Only try to set pixel format if we do not currently have one
  int currentPixelFormat = GetPixelFormat(hDC);
  // if there is a current pixel format, then make sure it
  // supports OpenGL
  if (currentPixelFormat != 0)
    {
685
686
687
    DescribePixelFormat(hDC, currentPixelFormat,sizeof(pfd), &pfd);
    if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL))
      {
688
#ifdef UNICODE
689
      MessageBox(WindowFromDC(hDC),
690
691
692
                 L"Invalid pixel format, no OpenGL support",
                 L"Error",
                 MB_ICONERROR | MB_OK);
693
#else
694
      MessageBox(WindowFromDC(hDC),
695
696
697
                 "Invalid pixel format, no OpenGL support",
                 "Error",
                 MB_ICONERROR | MB_OK);
698
#endif
699
700
701
702
703
704
705
706
707
      if (this->HasObserver(vtkCommand::ExitEvent))
        {
        this->InvokeEvent(vtkCommand::ExitEvent, NULL);
        return;
        }
      else
        {
        exit(1);
        }
708
      }
LYMB Demo's avatar
LYMB Demo committed
709
    }
710
711
  else
    {
712
    // hDC has no current PixelFormat, so
713
714
715
    pixelFormat = ChoosePixelFormat(hDC, &pfd);
    if (pixelFormat == 0)
      {
716
#ifdef UNICODE
717
718
      MessageBox(WindowFromDC(hDC), L"ChoosePixelFormat failed.", L"Error",
                 MB_ICONERROR | MB_OK);
719
#else
720
721
      MessageBox(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error",
                 MB_ICONERROR | MB_OK);
722
#endif
723
724
725
726
      if (this->HasObserver(vtkCommand::ExitEvent))
        {
        this->InvokeEvent(vtkCommand::ExitEvent, NULL);
        return;
727
        }
728
      else
729
        {
730
731
732
        exit(1);
        }
      }
733
734
    DescribePixelFormat(hDC, pixelFormat,sizeof(pfd), &pfd);
    if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE)
735
736
      {
      // int err = GetLastError();
737
#ifdef UNICODE
738
739
      MessageBox(WindowFromDC(hDC), L"SetPixelFormat failed.", L"Error",
                 MB_ICONERROR | MB_OK);
740
#else
741
742
      MessageBox(WindowFromDC(hDC), "SetPixelFormat failed.", "Error",
                 MB_ICONERROR | MB_OK);
743
#endif
744
745
746
747
      if (this->HasObserver(vtkCommand::ExitEvent))
        {
        this->InvokeEvent(vtkCommand::ExitEvent, NULL);
        return;
748
        }
749
750
751
752
753
      else
        {
        exit(1);
        }
      }
754
755
756
    }
  if (debug && (dwFlags & PFD_STEREO) && !(pfd.dwFlags & PFD_STEREO))
    {
757
758
    vtkGenericWarningMacro("No Stereo Available!");
    this->StereoCapableWindow = 0;
LYMB Demo's avatar
LYMB Demo committed
759
760
761
    }
}

762
void vtkWin32OpenGLRenderWindow::SetupPalette(HDC hDC)
LYMB Demo's avatar
LYMB Demo committed
763
{
764
765
766
767
  int pixelFormat = GetPixelFormat(hDC);
  PIXELFORMATDESCRIPTOR pfd;
  LOGPALETTE* pPal;
  int paletteSize;
LYMB Demo's avatar
LYMB Demo committed
768

769
  DescribePixelFormat(hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
LYMB Demo's avatar
LYMB Demo committed
770

771
  if (pfd.dwFlags & PFD_NEED_PALETTE) {
772
  paletteSize = 1 << pfd.cColorBits;
773
  } else {
774
  return;
775
776
777
778
779
780
781
782
783
  }

  pPal = (LOGPALETTE*)
    malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
  pPal->palVersion = 0x300;
  pPal->palNumEntries = paletteSize;

  /* build a simple RGB color palette */
  {
784
785
786
787
788
789
790
791
792
793
794
795
796
797
  int redMask = (1 << pfd.cRedBits) - 1;
  int greenMask = (1 << pfd.cGreenBits) - 1;
  int blueMask = (1 << pfd.cBlueBits) - 1;
  int i;

  for (i=0; i<paletteSize; ++i) {
  pPal->palPalEntry[i].peRed =
    (((i >> pfd.cRedShift) & redMask) * 255) / redMask;
  pPal->palPalEntry[i].peGreen =
    (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
  pPal->palPalEntry[i].peBlue =
    (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
  pPal->palPalEntry[i].peFlags = 0;
  }
798
  }
LYMB Demo's avatar
LYMB Demo committed
799

800
801
  this->Palette = CreatePalette(pPal);
  free(pPal);
LYMB Demo's avatar
LYMB Demo committed
802

803
  if (this->Palette) {
804
805
  this->OldPalette = SelectPalette(hDC, this->Palette, FALSE);
  RealizePalette(hDC);
806
  }
LYMB Demo's avatar
LYMB Demo committed
807
808
}

LYMB Demo's avatar
LYMB Demo committed
809

810
LRESULT vtkWin32OpenGLRenderWindow::MessageProc(HWND hWnd, UINT message,
811
                                                WPARAM wParam, LPARAM lParam)
LYMB Demo's avatar
LYMB Demo committed
812
{
813
  switch (message)
LYMB Demo's avatar
LYMB Demo committed
814
815
    {
    case WM_CREATE:
816
817
818
819
820
    {
    // nothing to be done here, opengl is initilized after the call to
    // create now
    return 0;
    }
LYMB Demo's avatar
LYMB Demo committed
821
    case WM_DESTROY:
822
823
      this->Clean();
      if (this->DeviceContext)
824
        {
825
826
827
        ReleaseDC(this->WindowId, this->DeviceContext);
        this->DeviceContext = NULL;
        this->WindowId = NULL;
828
        }
829
      return 0;
LYMB Demo's avatar
LYMB Demo committed
830
    case WM_SIZE:
831
      /* track window size changes */
832
      if (this->ContextId)
833
        {
834
835
        this->SetSize((int) LOWORD(lParam),(int) HIWORD(lParam));
        return 0;
836
        }
LYMB Demo's avatar
LYMB Demo committed
837
    case WM_PALETTECHANGED:
838
      /* realize palette if this is *not* the current window */
839
      if (this->ContextId && this->Palette && (HWND) wParam != hWnd)
840
        {
841
842
        SelectPalette(this->DeviceContext, this->OldPalette, FALSE);
        UnrealizeObject(this->Palette);
843
        this->OldPalette = SelectPalette(this->DeviceContext,
844
845
846
                                         this->Palette, FALSE);
        RealizePalette(this->DeviceContext);
        this->Render();
847
848
        }
      break;
LYMB Demo's avatar
LYMB Demo committed
849
    case WM_QUERYNEWPALETTE:
850
      /* realize palette if this is the current window */
851
      if (this->ContextId && this->Palette)
852
        {
853
854
        SelectPalette(this->DeviceContext, this->OldPalette, FALSE);
        UnrealizeObject(this->Palette);
855
        this->OldPalette = SelectPalette(this->DeviceContext,
856
857
858
859
                                         this->Palette, FALSE);
        RealizePalette(this->DeviceContext);
        this->Render();
        return TRUE;
860
861
        }
      break;
LYMB Demo's avatar
LYMB Demo committed
862
    case WM_PAINT:
863
864
865
    {
    PAINTSTRUCT ps;
    BeginPaint(hWnd, &ps);
866
    if (this->ContextId)
867
      {
868
      this->Render();
869
      }
870
871
872
873
    EndPaint(hWnd, &ps);
    return 0;
    }
    break;
874
875
    case WM_ERASEBKGND:
      return TRUE;
876
    case WM_SETCURSOR:
877
878
879
880
881
882
      if (HTCLIENT == LOWORD(lParam))
        {
        this->SetCurrentCursor(this->GetCurrentCursor());
        return TRUE;
        }
      break;
LYMB Demo's avatar
LYMB Demo committed
883
    default:
884
      this->InvokeEvent(vtkCommand::RenderWindowMessageEvent, &message);
885
      break;
LYMB Demo's avatar
LYMB Demo committed
886
    }
887
  return DefWindowProc(hWnd, message, wParam, lParam);
LYMB Demo's avatar
LYMB Demo committed
888
889
890
}


891
void vtkWin32OpenGLRenderWindow::InitializeApplication()
892
{
Kyle Lutz's avatar
Kyle Lutz committed
893
  // get the application instance if we don't have one already
894
895
  if (!this->ApplicationInstance)
    {
Ken Martin's avatar
Ken Martin committed
896
897
898
    // if we have a parent window get the app instance from it
    if (this->ParentId)
      {
899
      this->ApplicationInstance = (HINSTANCE)vtkGetWindowLong(this->ParentId,vtkGWL_HINSTANCE);
Ken Martin's avatar
Ken Martin committed
900
901
902
903
904
      }
    else
      {
      this->ApplicationInstance = GetModuleHandle(NULL); /*AfxGetInstanceHandle();*/
      }
905
906
907
    }
}

908
void vtkWin32OpenGLRenderWindow::CreateAWindow()
909
{
Frederic TINGAUD's avatar
Frederic TINGAUD committed
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938

  WNDCLASS wndClass;
  // has the class been registered ?
#ifdef UNICODE
  if (!GetClassInfo(this->ApplicationInstance,L"vtkOpenGL",&wndClass))
#else
  if (!GetClassInfo(this->ApplicationInstance,"vtkOpenGL",&wndClass))
#endif
    {
    wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wndClass.lpfnWndProc = vtkWin32OpenGLRenderWindow::WndProc;
    wndClass.cbClsExtra = 0;
    wndClass.hInstance = this->ApplicationInstance;
    wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wndClass.lpszMenuName = NULL;
#ifdef UNICODE
    wndClass.lpszClassName = L"vtkOpenGL";
#else
    wndClass.lpszClassName = "vtkOpenGL";
#endif
    // vtk doesn't use the first extra vtkLONG's worth of bytes,
    // but app writers may want them, so we provide them. VTK
    // does use the second vtkLONG's worth of bytes of extra space.
    wndClass.cbWndExtra = 2 * sizeof(vtkLONG);
    RegisterClass(&wndClass);
    }

Mathieu Malaterre's avatar
Mathieu Malaterre committed
939
  if(this->WindowIdReferenceCount == 0)
940
    {
Mathieu Malaterre's avatar
Mathieu Malaterre committed
941
    static int count = 1;
942
    char *windowName;
943

944
945
946
    if (!this->WindowId)
      {
      this->DeviceContext = 0;
947
948

      int len = static_cast<int>(strlen("Visualization Toolkit - Win32OpenGL #"))
949
        + (int)ceil( (double) log10( (double)(count+1) ) )
950
        + 1;
951
952
953
954
      windowName = new char [ len ];
      sprintf(windowName,"Visualization Toolkit - Win32OpenGL #%i",count++);
      this->SetWindowName(windowName);
      delete [] windowName;
955

956
#ifdef UNICODE
957
958
      wchar_t *wname = new wchar_t [mbstowcs(NULL, this->WindowName, 32000)+1];
      mbstowcs(wname, this->WindowName, 32000);
959
#endif
960
961
962
963
      int x = ((this->Position[0] >= 0) ? this->Position[0] : 5);
      int y = ((this->Position[1] >= 0) ? this->Position[1] : 5);
      int height = ((this->Size[1] > 0) ? this->Size[1] : 300);
      int width = ((this->Size[0] > 0) ? this->Size[0] : 300);
964

965
966
967
      /* create window */
      if (this->ParentId)
        {
968
#ifdef UNICODE
969
970
971
972
973
        this->WindowId = CreateWindow(
          L"vtkOpenGL", wname,
          WS_CHILD | WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/,
          x, y, width, height,
          this->ParentId, NULL, this->ApplicationInstance, NULL);
974
#else
975
976
977
978
979
        this->WindowId = CreateWindow(
          "vtkOpenGL", this->WindowName,
          WS_CHILD | WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/,
          x, y, width, height,
          this->ParentId, NULL, this->ApplicationInstance, NULL);
980
#endif
LYMB Demo's avatar
LYMB Demo committed
981
982
983
        }
      else
        {
984
985
986
987
988
989
990
991
992
        DWORD style;
        if (this->Borders)
          {
          style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/;
          }
        else
          {
          style = WS_POPUP | WS_CLIPCHILDREN /*| WS_CLIPSIBLINGS*/;
          }
993
994
995
996
997
998
999
1000
1001
1002
        RECT r;
        r.left = x;
        r.top = y;
        r.right = r.left + width;
        r.bottom = r.top + height;
        BOOL result = AdjustWindowRect( &r, style, FALSE );
        if (!result)
          {
          vtkErrorMacro("AdjustWindowRect failed, error: " << GetLastError());
          }
1003
#ifdef UNICODE
1004
1005
        this->WindowId = CreateWindow(
          L"vtkOpenGL", wname, style,
1006
          x, y, r.right-r.left, r.bottom-r.top,
1007
          NULL, NULL, this->ApplicationInstance, NULL);