1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkOpenGLContextDevice2D.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "vtkOpenGLContextDevice2D.h"
17 
18 #include "vtkMathTextUtilities.h"
19 #include "vtkTextRendererStringToImage.h"
20 
21 #include "vtkVector.h"
22 #include "vtkRect.h"
23 #include "vtkPen.h"
24 #include "vtkBrush.h"
25 #include "vtkTextProperty.h"
26 #include "vtkPoints2D.h"
27 #include "vtkMatrix3x3.h"
28 #include "vtkFloatArray.h"
29 #include "vtkSmartPointer.h"
30 
31 #include "vtkMath.h"
32 #include "vtkObjectFactory.h"
33 
34 #include "vtkViewport.h"
35 #include "vtkWindow.h"
36 
37 #include "vtkTexture.h"
38 #include "vtkImageData.h"
39 
40 #include "vtkOpenGLRenderer.h"
41 #include "vtkOpenGLRenderWindow.h"
42 #include "vtkOpenGLError.h"
43 
44 #include "vtkObjectFactory.h"
45 
46 #include "vtkOpenGLContextDevice2DPrivate.h"
47 #include "vtkAbstractContextBufferId.h"
48 
49 #include "vtkOpenGLShaderCache.h"
50 
51 #include <algorithm>
52 
53 //-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkOpenGLContextDevice2D)54 vtkStandardNewMacro(vtkOpenGLContextDevice2D)
55 
56 //-----------------------------------------------------------------------------
57 vtkOpenGLContextDevice2D::vtkOpenGLContextDevice2D()
58 {
59   this->Renderer = 0;
60   this->InRender = false;
61   this->TextRenderer = vtkTextRendererStringToImage::New();
62   this->Storage = new vtkOpenGLContextDevice2D::Private;
63   this->RenderWindow = NULL;
64   this->MaximumMarkerCacheSize = 20;
65 }
66 
67 //-----------------------------------------------------------------------------
~vtkOpenGLContextDevice2D()68 vtkOpenGLContextDevice2D::~vtkOpenGLContextDevice2D()
69 {
70   while (!this->MarkerCache.empty())
71     {
72     this->MarkerCache.back().Value->Delete();
73     this->MarkerCache.pop_back();
74     }
75 
76   this->TextRenderer->Delete();
77   delete this->Storage;
78 }
79 
80 //-----------------------------------------------------------------------------
Begin(vtkViewport * viewport)81 void vtkOpenGLContextDevice2D::Begin(vtkViewport* viewport)
82 {
83   vtkOpenGLClearErrorMacro();
84   // Need the actual pixel size of the viewport - ask OpenGL.
85   GLint vp[4];
86   glGetIntegerv(GL_VIEWPORT, vp);
87   this->Storage->Offset.Set(static_cast<int>(vp[0]),
88                             static_cast<int>(vp[1]));
89 
90   this->Storage->Dim.Set(static_cast<int>(vp[2]),
91                          static_cast<int>(vp[3]));
92 
93   // push a 2D matrix on the stack
94   glMatrixMode(GL_PROJECTION);
95   glPushMatrix();
96   glLoadIdentity();
97   float offset = 0.5;
98   glOrtho(offset, vp[2]+offset-1.0,
99           offset, vp[3]+offset-1.0,
100           -2000, 2000);
101 
102   glMatrixMode(GL_MODELVIEW);
103   glPushMatrix();
104   glLoadIdentity();
105 
106   // Store the previous state before changing it
107   this->Storage->SaveGLState();
108   glDisable(GL_LIGHTING);
109   glDisable(GL_DEPTH_TEST);
110   glEnable(GL_BLEND);
111 
112   this->Renderer = vtkRenderer::SafeDownCast(viewport);
113 
114   vtkOpenGLRenderWindow *renWin = vtkOpenGLRenderWindow::SafeDownCast(this->Renderer->GetRenderWindow());
115   renWin->GetShaderCache()->ReleaseCurrentShader();
116 
117   // Enable simple line, point and polygon antialiasing if multisampling is on.
118   if (this->Renderer->GetRenderWindow()->GetMultiSamples())
119     {
120     glEnable(GL_LINE_SMOOTH);
121     glEnable(GL_POINT_SMOOTH);
122     glEnable(GL_POLYGON_SMOOTH);
123     }
124 
125   // Make sure we are on the default texture setting
126   glBindTexture(GL_TEXTURE_2D, 0);
127 
128   this->InRender = true;
129   vtkOpenGLCheckErrorMacro("failed after Begin");
130 }
131 
132 //-----------------------------------------------------------------------------
End()133 void vtkOpenGLContextDevice2D::End()
134 {
135   if (!this->InRender)
136     {
137     return;
138     }
139 
140   vtkOpenGLClearErrorMacro();
141 
142   // push a 2D matrix on the stack
143   glMatrixMode(GL_PROJECTION);
144   glPopMatrix();
145   glMatrixMode(GL_MODELVIEW);
146   glPopMatrix();
147 
148   // Restore the GL state that we changed
149   this->Storage->RestoreGLState();
150 
151   // Disable simple line, point and polygon antialiasing if multisampling is on.
152   if (this->Renderer->GetRenderWindow()->GetMultiSamples())
153     {
154     glDisable(GL_LINE_SMOOTH);
155     glDisable(GL_POINT_SMOOTH);
156     glDisable(GL_POLYGON_SMOOTH);
157     }
158 
159   this->RenderWindow = NULL;
160   this->InRender = false;
161 
162   vtkOpenGLCheckErrorMacro("failed after End");
163 }
164 
165 // ----------------------------------------------------------------------------
BufferIdModeBegin(vtkAbstractContextBufferId * bufferId)166 void vtkOpenGLContextDevice2D::BufferIdModeBegin(
167   vtkAbstractContextBufferId *bufferId)
168 {
169   assert("pre: not_yet" && !this->GetBufferIdMode());
170   assert("pre: bufferId_exists" && bufferId!=0);
171 
172   vtkOpenGLClearErrorMacro();
173 
174   this->BufferId=bufferId;
175 
176   // Save OpenGL state.
177   this->Storage->SaveGLState(true);
178 
179   int lowerLeft[2];
180   int usize, vsize;
181   this->Renderer->GetTiledSizeAndOrigin(&usize,&vsize,lowerLeft,lowerLeft+1);
182 
183   glMatrixMode(GL_PROJECTION);
184   glPushMatrix();
185   glLoadIdentity();
186   glOrtho( 0.5, usize+0.5,
187            0.5, vsize+0.5,
188           -1, 1);
189   glMatrixMode(GL_MODELVIEW);
190   glPushMatrix();
191   glLoadIdentity();
192 
193   glDrawBuffer(GL_BACK_LEFT);
194   glClearColor(0.0,0.0,0.0,0.0); // id=0 means no hit, just background
195   glClear(GL_COLOR_BUFFER_BIT);
196   glDisable(GL_LIGHTING);
197   glDisable(GL_ALPHA_TEST);
198   glDisable(GL_STENCIL_TEST);
199   glDisable(GL_DEPTH_TEST);
200   glDisable(GL_BLEND);
201 
202   vtkOpenGLCheckErrorMacro("failed after BufferIdModeBegin");
203 
204   assert("post: started" && this->GetBufferIdMode());
205 }
206 
207 // ----------------------------------------------------------------------------
BufferIdModeEnd()208 void vtkOpenGLContextDevice2D::BufferIdModeEnd()
209 {
210   assert("pre: started" && this->GetBufferIdMode());
211 
212   vtkOpenGLClearErrorMacro();
213 
214   // Assume the renderer has been set previously during rendering (sse Begin())
215   int lowerLeft[2];
216   int usize, vsize;
217   this->Renderer->GetTiledSizeAndOrigin(&usize,&vsize,lowerLeft,lowerLeft+1);
218   this->BufferId->SetValues(lowerLeft[0],lowerLeft[1]);
219 
220   // Restore OpenGL state (only if it's different to avoid too much state
221   // change).
222   glMatrixMode(GL_PROJECTION);
223   glPopMatrix();
224   glMatrixMode(GL_MODELVIEW);
225   glPopMatrix();
226 
227   this->Storage->RestoreGLState(true);
228 
229   this->BufferId=0;
230 
231   vtkOpenGLCheckErrorMacro("failed after BufferIdModeEnd");
232 
233   assert("post: done" && !this->GetBufferIdMode());
234 }
235 
236 //-----------------------------------------------------------------------------
DrawPoly(float * f,int n,unsigned char * colors,int nc)237 void vtkOpenGLContextDevice2D::DrawPoly(float *f, int n, unsigned char *colors,
238                                         int nc)
239 {
240   assert("f must be non-null" && f != NULL);
241   assert("n must be greater than 0" && n > 0);
242 
243   vtkOpenGLClearErrorMacro();
244 
245   this->SetLineType(this->Pen->GetLineType());
246   this->SetLineWidth(this->Pen->GetWidth());
247 
248   if (colors)
249     {
250     glEnableClientState(GL_COLOR_ARRAY);
251     glColorPointer(nc, GL_UNSIGNED_BYTE, 0, colors);
252     }
253   else
254     {
255     glColor4ubv(this->Pen->GetColor());
256     }
257   glEnableClientState(GL_VERTEX_ARRAY);
258   glVertexPointer(2, GL_FLOAT, 0, f);
259   glDrawArrays(GL_LINE_STRIP, 0, n);
260   glDisableClientState(GL_VERTEX_ARRAY);
261   if (colors)
262     {
263     glDisableClientState(GL_COLOR_ARRAY);
264     }
265 
266   // Restore line type and width.
267   this->SetLineType(vtkPen::SOLID_LINE);
268   this->SetLineWidth(1.0f);
269 
270   vtkOpenGLCheckErrorMacro("failed after DrawPoly");
271 }
272 
273 //-----------------------------------------------------------------------------
DrawPoints(float * f,int n,unsigned char * c,int nc)274 void vtkOpenGLContextDevice2D::DrawPoints(float *f, int n, unsigned char *c,
275                                           int nc)
276 {
277   vtkOpenGLClearErrorMacro();
278 
279   if (f && n > 0)
280     {
281     this->SetPointSize(this->Pen->GetWidth());
282     glEnableClientState(GL_VERTEX_ARRAY);
283     if (c && nc)
284       {
285       glEnableClientState(GL_COLOR_ARRAY);
286       glColorPointer(nc, GL_UNSIGNED_BYTE, 0, c);
287       }
288     else
289       {
290       glColor4ubv(this->Pen->GetColor());
291       }
292     glVertexPointer(2, GL_FLOAT, 0, f);
293     glDrawArrays(GL_POINTS, 0, n);
294     glDisableClientState(GL_VERTEX_ARRAY);
295     if (c && nc)
296       {
297       glDisableClientState(GL_COLOR_ARRAY);
298       }
299     }
300   else
301     {
302     vtkWarningMacro(<< "Points supplied that were not of type float.");
303     }
304 
305   vtkOpenGLCheckErrorMacro("failed after DrawPoints");
306 }
307 
308 //-----------------------------------------------------------------------------
DrawPointSprites(vtkImageData * sprite,float * points,int n,unsigned char * colors,int nc_comps)309 void vtkOpenGLContextDevice2D::DrawPointSprites(vtkImageData *sprite,
310                                                 float *points, int n,
311                                                 unsigned char *colors,
312                                                 int nc_comps)
313 {
314   vtkOpenGLClearErrorMacro();
315   if (points && n > 0)
316     {
317     this->SetPointSize(this->Pen->GetWidth());
318     if (sprite)
319       {
320       if (!this->Storage->SpriteTexture)
321         {
322         this->Storage->SpriteTexture = vtkTexture::New();
323         }
324       int properties = this->Brush->GetTextureProperties();
325       this->Storage->SpriteTexture->SetInputData(sprite);
326       this->Storage->SpriteTexture->SetRepeat(properties & vtkContextDevice2D::Repeat);
327       this->Storage->SpriteTexture->SetInterpolate(properties & vtkContextDevice2D::Linear);
328       glEnable(GL_TEXTURE_2D);
329       this->Storage->SpriteTexture->Render(this->Renderer);
330       }
331 
332     // Must emulate the point sprites - slower but at least they see something.
333     GLfloat width = 1.0;
334     glGetFloatv(GL_POINT_SIZE, &width);
335     width /= 2.0;
336 
337     // Need to get the model view matrix for scaling factors...
338     GLfloat mv[16];
339     glGetFloatv(GL_MODELVIEW_MATRIX, mv);
340     float xWidth = width / mv[0];
341     float yWidth = width / mv[5];
342 
343     // Four 2D points on the quad.
344     float p[4 * 2] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
345 
346     // This will be the same every time
347     float texCoord[] = { 0.0, 0.0,
348                          1.0, 0.0,
349                          1.0, 1.0,
350                          0.0, 1.0 };
351 
352     if (!colors || !nc_comps)
353       {
354       glColor4ubv(this->Pen->GetColor());
355       }
356     glEnableClientState(GL_VERTEX_ARRAY);
357     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
358     glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
359 
360     for (int i = 0; i < n; ++i)
361       {
362       p[0] = points[2*i] - xWidth;
363       p[1] = points[2*i+1] - yWidth;
364       p[2] = points[2*i] + xWidth;
365       p[3] = points[2*i+1] - yWidth;
366       p[4] = points[2*i] + xWidth;
367       p[5] = points[2*i+1] + yWidth;
368       p[6] = points[2*i] - xWidth;
369       p[7] = points[2*i+1] + yWidth;
370 
371       // If we have a color array, set the color for each quad.
372       if (colors && nc_comps)
373         {
374         if (nc_comps == 3)
375           {
376           glColor3ubv(&colors[3 * i]);
377           }
378         else if (nc_comps == 4)
379           {
380           glColor4ubv(&colors[4 * i]);
381           }
382         }
383 
384       glVertexPointer(2, GL_FLOAT, 0, p);
385       glDrawArrays(GL_QUADS, 0, 4);
386       }
387     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
388     glDisableClientState(GL_VERTEX_ARRAY);
389 
390     if (sprite)
391       {
392       this->Storage->SpriteTexture->PostRender(this->Renderer);
393       glDisable(GL_TEXTURE_2D);
394       }
395     }
396   else
397     {
398     vtkWarningMacro(<< "Points supplied without a valid image or pointer.");
399     }
400   vtkOpenGLCheckErrorMacro("failed after DrawPointSprites");
401 }
402 
403 //-----------------------------------------------------------------------------
DrawMarkers(int shape,bool highlight,float * points,int n,unsigned char * colors,int nc_comps)404 void vtkOpenGLContextDevice2D::DrawMarkers(int shape, bool highlight,
405                                            float *points, int n,
406                                            unsigned char *colors, int nc_comps)
407 {
408   // Get a point sprite for the shape
409   vtkImageData *sprite = this->GetMarker(shape, this->Pen->GetWidth(),
410                                          highlight);
411   this->DrawPointSprites(sprite, points, n, colors, nc_comps);
412 }
413 
414 //-----------------------------------------------------------------------------
DrawQuad(float * f,int n)415 void vtkOpenGLContextDevice2D::DrawQuad(float *f, int n)
416 {
417   vtkOpenGLClearErrorMacro();
418   if (!f || n <= 0)
419     {
420     vtkWarningMacro(<< "Points supplied that were not of type float.");
421     return;
422     }
423   glColor4ubv(this->Brush->GetColor());
424   float* texCoord = 0;
425   if (this->Brush->GetTexture())
426     {
427     this->SetTexture(this->Brush->GetTexture(),
428                      this->Brush->GetTextureProperties());
429     glEnable(GL_TEXTURE_2D);
430     this->Storage->Texture->Render(this->Renderer);
431     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
432     texCoord = this->Storage->TexCoords(f, n);
433     glTexCoordPointer(2, GL_FLOAT, 0, &texCoord[0]);
434     }
435   glEnableClientState(GL_VERTEX_ARRAY);
436   glVertexPointer(2, GL_FLOAT, 0, f);
437   glDrawArrays(GL_QUADS, 0, n);
438   glDisableClientState(GL_VERTEX_ARRAY);
439   if (this->Storage->Texture)
440     {
441     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
442     this->Storage->Texture->PostRender(this->Renderer);
443     glDisable(GL_TEXTURE_2D);
444     delete [] texCoord;
445     }
446   vtkOpenGLCheckErrorMacro("failed after DrawQuad");
447 }
448 
449 //-----------------------------------------------------------------------------
DrawQuadStrip(float * f,int n)450 void vtkOpenGLContextDevice2D::DrawQuadStrip(float *f, int n)
451 {
452   vtkOpenGLClearErrorMacro();
453   if (!f || n <= 0)
454     {
455     vtkWarningMacro(<< "Points supplied that were not of type float.");
456     return;
457     }
458   glColor4ubv(this->Brush->GetColor());
459   float* texCoord = 0;
460   if (this->Brush->GetTexture())
461     {
462     this->SetTexture(this->Brush->GetTexture(),
463                      this->Brush->GetTextureProperties());
464     glEnable(GL_TEXTURE_2D);
465     this->Storage->Texture->Render(this->Renderer);
466     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
467     texCoord = this->Storage->TexCoords(f, n);
468     glTexCoordPointer(2, GL_FLOAT, 0, &texCoord[0]);
469     }
470   glEnableClientState(GL_VERTEX_ARRAY);
471   glVertexPointer(2, GL_FLOAT, 0, f);
472   glDrawArrays(GL_QUAD_STRIP, 0, n);
473   glDisableClientState(GL_VERTEX_ARRAY);
474   if (this->Storage->Texture)
475     {
476     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
477     this->Storage->Texture->PostRender(this->Renderer);
478     glDisable(GL_TEXTURE_2D);
479     delete [] texCoord;
480     }
481   vtkOpenGLCheckErrorMacro("failed after DrawQuadStrip");
482 }
483 //-----------------------------------------------------------------------------
DrawPolygon(float * f,int n)484 void vtkOpenGLContextDevice2D::DrawPolygon(float *f, int n)
485 {
486   vtkOpenGLClearErrorMacro();
487   if (!f || n <= 0)
488     {
489     vtkWarningMacro(<< "Points supplied that were not of type float.");
490     return;
491     }
492   glColor4ubv(this->Brush->GetColor());
493   float* texCoord = 0;
494   if (this->Brush->GetTexture())
495     {
496     this->SetTexture(this->Brush->GetTexture(),
497                      this->Brush->GetTextureProperties());
498     glEnable(GL_TEXTURE_2D);
499     this->Storage->Texture->Render(this->Renderer);
500     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
501     texCoord = this->Storage->TexCoords(f, n);
502     glTexCoordPointer(2, GL_FLOAT, 0, &texCoord[0]);
503     }
504   glEnableClientState(GL_VERTEX_ARRAY);
505   glVertexPointer(2, GL_FLOAT, 0, f);
506   glDrawArrays(GL_POLYGON, 0, n);
507   glDisableClientState(GL_VERTEX_ARRAY);
508   if (this->Storage->Texture)
509     {
510     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
511     this->Storage->Texture->PostRender(this->Renderer);
512     glDisable(GL_TEXTURE_2D);
513     delete [] texCoord;
514     }
515   vtkOpenGLCheckErrorMacro("failed after DrawPolygon");
516 }
517 
518 //-----------------------------------------------------------------------------
DrawEllipseWedge(float x,float y,float outRx,float outRy,float inRx,float inRy,float startAngle,float stopAngle)519 void vtkOpenGLContextDevice2D::DrawEllipseWedge(float x, float y, float outRx,
520                                                 float outRy, float inRx,
521                                                 float inRy, float startAngle,
522                                                 float stopAngle)
523 
524 {
525   assert("pre: positive_outRx" && outRx>=0.0f);
526   assert("pre: positive_outRy" && outRy>=0.0f);
527   assert("pre: positive_inRx" && inRx>=0.0f);
528   assert("pre: positive_inRy" && inRy>=0.0f);
529   assert("pre: ordered_rx" && inRx<=outRx);
530   assert("pre: ordered_ry" && inRy<=outRy);
531 
532   if(outRy==0.0f && outRx==0.0f)
533     {
534     // we make sure maxRadius will never be null.
535     return;
536     }
537 
538   vtkOpenGLClearErrorMacro();
539 
540   int iterations=this->GetNumberOfArcIterations(outRx,outRy,startAngle,
541                                                 stopAngle);
542 
543   float *p=new float[4*(iterations+1)];
544 
545   // step in radians.
546   double step =
547     vtkMath::RadiansFromDegrees(stopAngle-startAngle)/(iterations);
548 
549   // step have to be lesser or equal to maxStep computed inside
550   // GetNumberOfIterations()
551 
552   double rstart=vtkMath::RadiansFromDegrees(startAngle);
553 
554   // the A vertices (0,2,4,..) are on the inner side
555   // the B vertices (1,3,5,..) are on the outer side
556   // (A and B vertices terms come from triangle strip definition in
557   // OpenGL spec)
558   // we are iterating counterclockwise
559 
560   int i=0;
561   while(i<=iterations)
562     {
563     // A vertex (inner side)
564     double a=rstart+i*step;
565     p[4*i  ] = inRx * cos(a) + x;
566     p[4*i+1] = inRy * sin(a) + y;
567 
568     // B vertex (outer side)
569     p[4*i+2] = outRx * cos(a) + x;
570     p[4*i+3] = outRy * sin(a) + y;
571 
572     ++i;
573     }
574 
575   glColor4ubv(this->Brush->GetColor());
576   glEnableClientState(GL_VERTEX_ARRAY);
577   glVertexPointer(2, GL_FLOAT, 0, p);
578   glDrawArrays(GL_TRIANGLE_STRIP, 0, 2*(iterations+1));
579   glDisableClientState(GL_VERTEX_ARRAY);
580 
581   delete[] p;
582 
583   vtkOpenGLCheckErrorMacro("failed after DrawEllipseWedge");
584 }
585 
586 // ----------------------------------------------------------------------------
DrawEllipticArc(float x,float y,float rX,float rY,float startAngle,float stopAngle)587 void vtkOpenGLContextDevice2D::DrawEllipticArc(float x, float y, float rX,
588                                                float rY, float startAngle,
589                                                float stopAngle)
590 {
591   assert("pre: positive_rX" && rX>=0);
592   assert("pre: positive_rY" && rY>=0);
593 
594   if(rX==0.0f && rY==0.0f)
595     {
596     // we make sure maxRadius will never be null.
597     return;
598     }
599 
600   vtkOpenGLClearErrorMacro();
601 
602   int iterations = this->GetNumberOfArcIterations(rX, rY, startAngle, stopAngle);
603 
604   float *p = new float[2*(iterations+1)];
605 
606   // step in radians.
607   double step =
608     vtkMath::RadiansFromDegrees(stopAngle-startAngle)/(iterations);
609 
610   // step have to be lesser or equal to maxStep computed inside
611   // GetNumberOfIterations()
612   double rstart=vtkMath::RadiansFromDegrees(startAngle);
613 
614   // we are iterating counterclockwise
615   for(int i = 0; i <= iterations; ++i)
616     {
617     double a=rstart+i*step;
618     p[2*i  ] = rX * cos(a) + x;
619     p[2*i+1] = rY * sin(a) + y;
620     }
621 
622   this->SetLineType(this->Pen->GetLineType());
623   this->SetLineWidth(this->Pen->GetWidth());
624   glEnableClientState(GL_VERTEX_ARRAY);
625   glVertexPointer(2, GL_FLOAT, 0, p);
626   glColor4ubv(this->Brush->GetColor());
627   glDrawArrays(GL_TRIANGLE_FAN, 0, iterations+1);
628   glColor4ubv(this->Pen->GetColor());
629   glDrawArrays(GL_LINE_STRIP, 0, iterations+1);
630   glDisableClientState(GL_VERTEX_ARRAY);
631   // Restore line type and width.
632   this->SetLineType(vtkPen::SOLID_LINE);
633   this->SetLineWidth(1.0f);
634 
635   delete[] p;
636 
637   vtkOpenGLCheckErrorMacro("failed after DrawEllipseArc");
638 }
639 
640 // ----------------------------------------------------------------------------
GetNumberOfArcIterations(float rX,float rY,float startAngle,float stopAngle)641 int vtkOpenGLContextDevice2D::GetNumberOfArcIterations(float rX,
642                                                        float rY,
643                                                        float startAngle,
644                                                        float stopAngle)
645 {
646   assert("pre: positive_rX" && rX>=0.0f);
647   assert("pre: positive_rY" && rY>=0.0f);
648   assert("pre: not_both_null" && (rX>0.0 || rY>0.0));
649 
650 // 1.0: pixel precision. 0.5 (subpixel precision, useful with multisampling)
651   double error = 4.0; // experience shows 4.0 is visually enough.
652 
653   // The tessellation is the most visible on the biggest radius.
654   double maxRadius;
655   if(rX >= rY)
656     {
657     maxRadius = rX;
658     }
659   else
660     {
661     maxRadius = rY;
662     }
663 
664   if(error > maxRadius)
665     {
666     // to make sure the argument of asin() is in a valid range.
667     error = maxRadius;
668     }
669 
670   // Angle of a sector so that its chord is `error' pixels.
671   // This is will be our maximum angle step.
672   double maxStep = 2.0 * asin(error / (2.0 * maxRadius));
673 
674   // ceil because we want to make sure we don't underestimate the number of
675   // iterations by 1.
676   return static_cast<int>(
677     ceil(vtkMath::RadiansFromDegrees(stopAngle - startAngle) / maxStep));
678 }
679 
680 //-----------------------------------------------------------------------------
AlignText(double orientation,float width,float height,float * p)681 void vtkOpenGLContextDevice2D::AlignText(double orientation, float width,
682                                          float height, float *p)
683 {
684   // Special case multiples of 90 as no transformation is required...
685   if (orientation > -0.0001 && orientation < 0.0001)
686     {
687     switch (this->TextProp->GetJustification())
688       {
689       case VTK_TEXT_LEFT:
690         break;
691       case VTK_TEXT_CENTERED:
692         p[0] -= floor(width / 2.0);
693         break;
694       case VTK_TEXT_RIGHT:
695         p[0] -= width;
696         break;
697       }
698     switch (this->TextProp->GetVerticalJustification())
699       {
700       case VTK_TEXT_BOTTOM:
701         break;
702       case VTK_TEXT_CENTERED:
703         p[1] -= floor(height / 2.0);
704         break;
705       case VTK_TEXT_TOP:
706         p[1] -= height;
707         break;
708       }
709     }
710   else if (orientation > 89.9999 && orientation < 90.0001)
711     {
712     switch (this->TextProp->GetJustification())
713       {
714       case VTK_TEXT_LEFT:
715         break;
716       case VTK_TEXT_CENTERED:
717         p[1] -= floor(height / 2.0);
718         break;
719       case VTK_TEXT_RIGHT:
720         p[1] -= height;
721         break;
722       }
723     switch (this->TextProp->GetVerticalJustification())
724       {
725       case VTK_TEXT_TOP:
726         break;
727       case VTK_TEXT_CENTERED:
728         p[0] -= floor(width / 2.0);
729         break;
730       case VTK_TEXT_BOTTOM:
731         p[0] -= width;
732         break;
733       }
734     }
735   else if (orientation > 179.9999 && orientation < 180.0001)
736     {
737     switch (this->TextProp->GetJustification())
738       {
739       case VTK_TEXT_RIGHT:
740         break;
741       case VTK_TEXT_CENTERED:
742         p[0] -= floor(width / 2.0);
743         break;
744       case VTK_TEXT_LEFT:
745         p[0] -= width;
746         break;
747       }
748     switch (this->TextProp->GetVerticalJustification())
749       {
750       case VTK_TEXT_TOP:
751         break;
752       case VTK_TEXT_CENTERED:
753         p[1] -= floor(height / 2.0);
754         break;
755       case VTK_TEXT_BOTTOM:
756         p[1] -= height;
757         break;
758       }
759     }
760   else if (orientation > 269.9999 && orientation < 270.0001)
761     {
762     switch (this->TextProp->GetJustification())
763       {
764       case VTK_TEXT_LEFT:
765         break;
766       case VTK_TEXT_CENTERED:
767         p[1] -= floor(height / 2.0);
768         break;
769       case VTK_TEXT_RIGHT:
770         p[1] -= height;
771         break;
772       }
773     switch (this->TextProp->GetVerticalJustification())
774       {
775       case VTK_TEXT_BOTTOM:
776         break;
777       case VTK_TEXT_CENTERED:
778         p[0] -= floor(width / 2.0);
779         break;
780       case VTK_TEXT_TOP:
781         p[0] -= width;
782         break;
783       }
784     }
785 }
786 
787 //-----------------------------------------------------------------------------
DrawString(float * point,const vtkStdString & string)788 void vtkOpenGLContextDevice2D::DrawString(float *point,
789                                           const vtkStdString &string)
790 {
791   this->DrawString(point, vtkUnicodeString::from_utf8(string));
792 }
793 
794 //-----------------------------------------------------------------------------
ComputeStringBounds(const vtkStdString & string,float bounds[4])795 void vtkOpenGLContextDevice2D::ComputeStringBounds(const vtkStdString &string,
796                                                    float bounds[4])
797 {
798   this->ComputeStringBounds(vtkUnicodeString::from_utf8(string), bounds);
799 }
800 
801 //-----------------------------------------------------------------------------
DrawString(float * point,const vtkUnicodeString & string)802 void vtkOpenGLContextDevice2D::DrawString(float *point,
803                                           const vtkUnicodeString &string)
804 {
805   vtkOpenGLClearErrorMacro();
806 
807   GLfloat mv[16];
808   glGetFloatv(GL_MODELVIEW_MATRIX, mv);
809   float xScale = mv[0];
810   float yScale = mv[5];
811 
812   float p[] = { std::floor(point[0] * xScale) / xScale,
813                 std::floor(point[1] * yScale) / yScale };
814 
815   // Cache rendered text strings
816   vtkTextureImageCache<UTF16TextPropertyKey>::CacheData &cache =
817       this->Storage->TextTextureCache.GetCacheData(
818         UTF16TextPropertyKey(this->TextProp, string));
819   vtkImageData* image = cache.ImageData;
820   if (image->GetNumberOfPoints() == 0 && image->GetNumberOfCells() == 0)
821     {
822     int textDims[2];
823     if (!this->TextRenderer->RenderString(this->TextProp, string, image,
824                                           textDims))
825       {
826       return;
827       }
828     cache.TextWidth = textDims[0];
829     cache.TextHeight = textDims[1];
830     }
831   vtkTexture* texture = cache.Texture;
832   glEnable(GL_TEXTURE_2D);
833   texture->Render(this->Renderer);
834 
835   int imgDims[3];
836   image->GetDimensions(imgDims);
837 
838   float width = cache.TextWidth / xScale;
839   float height = cache.TextHeight / yScale;
840 
841   float xw = cache.TextWidth / static_cast<float>(imgDims[0]);
842   float xh = cache.TextHeight / static_cast<float>(imgDims[1]);
843 
844   this->AlignText(this->TextProp->GetOrientation(), width, height, p);
845 
846   float points[] = { p[0]        , p[1],
847                      p[0] + width, p[1],
848                      p[0] + width, p[1] + height,
849                      p[0]        , p[1] + height };
850 
851   float texCoord[] = { 0.0f, 0.0f,
852                        xw,   0.0f,
853                        xw,   xh,
854                        0.0f, xh };
855 
856   glColor4ub(255, 255, 255, 255);
857   glEnableClientState(GL_VERTEX_ARRAY);
858   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
859   glVertexPointer(2, GL_FLOAT, 0, points);
860   glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
861   glDrawArrays(GL_QUADS, 0, 4);
862   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
863   glDisableClientState(GL_VERTEX_ARRAY);
864 
865   texture->PostRender(this->Renderer);
866   glDisable(GL_TEXTURE_2D);
867 
868   vtkOpenGLCheckErrorMacro("failed after DrawString");
869 }
870 
871 //-----------------------------------------------------------------------------
ComputeStringBounds(const vtkUnicodeString & string,float bounds[4])872 void vtkOpenGLContextDevice2D::ComputeStringBounds(const vtkUnicodeString &string,
873                                                    float bounds[4])
874 {
875   vtkVector2i box = this->TextRenderer->GetBounds(this->TextProp, string);
876   // Check for invalid bounding box
877   if (box[0] == VTK_INT_MIN || box[0] == VTK_INT_MAX ||
878       box[1] == VTK_INT_MIN || box[1] == VTK_INT_MAX)
879     {
880     bounds[0] = static_cast<float>(0);
881     bounds[1] = static_cast<float>(0);
882     bounds[2] = static_cast<float>(0);
883     bounds[3] = static_cast<float>(0);
884     return;
885     }
886   GLfloat mv[16];
887   glGetFloatv(GL_MODELVIEW_MATRIX, mv);
888   float xScale = mv[0];
889   float yScale = mv[5];
890   bounds[0] = static_cast<float>(0);
891   bounds[1] = static_cast<float>(0);
892   bounds[2] = static_cast<float>(box.GetX() / xScale);
893   bounds[3] = static_cast<float>(box.GetY() / yScale);
894 }
895 
896 //-----------------------------------------------------------------------------
DrawMathTextString(float point[2],const vtkStdString & string)897 void vtkOpenGLContextDevice2D::DrawMathTextString(float point[2],
898                                                   const vtkStdString &string)
899 {
900   vtkMathTextUtilities *mathText = vtkMathTextUtilities::GetInstance();
901   if (!mathText)
902     {
903     vtkWarningMacro(<<"MathText is not available to parse string "
904                     << string.c_str() << ". Install matplotlib and enable "
905                     "python to use MathText.");
906     return;
907     }
908 
909   vtkOpenGLClearErrorMacro();
910 
911   float p[] = { std::floor(point[0]), std::floor(point[1]) };
912 
913   // Cache rendered text strings
914   vtkTextureImageCache<UTF8TextPropertyKey>::CacheData &cache =
915     this->Storage->MathTextTextureCache.GetCacheData(
916       UTF8TextPropertyKey(this->TextProp, string));
917   vtkImageData* image = cache.ImageData;
918   if (image->GetNumberOfPoints() == 0 && image->GetNumberOfCells() == 0)
919     {
920     int textDims[2];
921     if (!mathText->RenderString(string.c_str(), image, this->TextProp,
922                                 this->RenderWindow->GetDPI(), textDims))
923       {
924       return;
925       }
926     cache.TextWidth = textDims[0];
927     cache.TextHeight = textDims[1];
928     }
929 
930   vtkTexture* texture = cache.Texture;
931   glEnable(GL_TEXTURE_2D);
932   texture->Render(this->Renderer);
933 
934   GLfloat mv[16];
935   glGetFloatv(GL_MODELVIEW_MATRIX, mv);
936   float xScale = mv[0];
937   float yScale = mv[5];
938 
939   int imgDims[3];
940   image->GetDimensions(imgDims);
941 
942   float width = cache.TextWidth / xScale;
943   float height = cache.TextHeight / yScale;
944 
945   float xw = cache.TextWidth / static_cast<float>(imgDims[0]);
946   float xh = cache.TextHeight / static_cast<float>(imgDims[1]);
947 
948   this->AlignText(this->TextProp->GetOrientation(), width, height, p);
949 
950   float points[] = { p[0]        , p[1],
951                      p[0] + width, p[1],
952                      p[0] + width, p[1] + height,
953                      p[0]        , p[1] + height };
954 
955   float texCoord[] = { 0.0f, 0.0f,
956                        xw,   0.0f,
957                        xw,   xh,
958                        0.0f, xh };
959 
960   glColor4ub(255, 255, 255, 255);
961   glEnableClientState(GL_VERTEX_ARRAY);
962   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
963   glVertexPointer(2, GL_FLOAT, 0, points);
964   glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
965   glDrawArrays(GL_QUADS, 0, 4);
966   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
967   glDisableClientState(GL_VERTEX_ARRAY);
968 
969   texture->PostRender(this->Renderer);
970   glDisable(GL_TEXTURE_2D);
971 
972   vtkOpenGLCheckErrorMacro("failed after DrawMathTexString");
973 }
974 
975 //-----------------------------------------------------------------------------
DrawImage(float p[2],float scale,vtkImageData * image)976 void vtkOpenGLContextDevice2D::DrawImage(float p[2], float scale,
977                                          vtkImageData *image)
978 {
979   vtkOpenGLClearErrorMacro();
980 
981   this->SetTexture(image);
982   glEnable(GL_TEXTURE_2D);
983   this->Storage->Texture->Render(this->Renderer);
984   int *extent = image->GetExtent();
985   float points[] = { p[0]                     , p[1],
986                      p[0]+scale*extent[1]+1.0f, p[1],
987                      p[0]+scale*extent[1]+1.0f, p[1]+scale*extent[3]+1.0f,
988                      p[0]                     , p[1]+scale*extent[3]+1.0f };
989 
990   float texCoord[] = { 0.0f, 0.0f,
991                        1.0f, 0.0f,
992                        1.0f, 1.0f,
993                        0.0f, 1.0f };
994 
995   glColor4ub(255, 255, 255, 255);
996   glEnableClientState(GL_VERTEX_ARRAY);
997   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
998   glVertexPointer(2, GL_FLOAT, 0, &points[0]);
999   glTexCoordPointer(2, GL_FLOAT, 0, &texCoord[0]);
1000   glDrawArrays(GL_QUADS, 0, 4);
1001   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1002   glDisableClientState(GL_VERTEX_ARRAY);
1003 
1004   this->Storage->Texture->PostRender(this->Renderer);
1005   glDisable(GL_TEXTURE_2D);
1006 
1007   vtkOpenGLCheckErrorMacro("failed after DrawImage");
1008 }
1009 
1010 //-----------------------------------------------------------------------------
DrawImage(const vtkRectf & pos,vtkImageData * image)1011 void vtkOpenGLContextDevice2D::DrawImage(const vtkRectf& pos,
1012                                          vtkImageData *image)
1013 {
1014   vtkOpenGLClearErrorMacro();
1015 
1016   vtkVector2f tex(1.0, 1.0);
1017   glEnable(GL_TEXTURE_2D);
1018   GLuint index = 0;
1019   if (this->Storage->PowerOfTwoTextures)
1020     {
1021     index = this->Storage->TextureFromImage(image, tex);
1022     }
1023   else
1024     {
1025     index = this->Storage->TextureFromImage(image, tex);
1026     }
1027 //  this->SetTexture(image);
1028 //  this->Storage->Texture->Render(this->Renderer);
1029   float points[] = { pos.GetX()              , pos.GetY(),
1030                      pos.GetX() + pos.GetWidth(), pos.GetY(),
1031                      pos.GetX() + pos.GetWidth(), pos.GetY() + pos.GetHeight(),
1032                      pos.GetX()              , pos.GetY() + pos.GetHeight() };
1033 
1034   float texCoord[] = { 0.0   , 0.0,
1035                        tex[0], 0.0,
1036                        tex[0], tex[1],
1037                        0.0   , tex[1] };
1038 
1039   glColor4ub(255, 255, 255, 255);
1040   glEnableClientState(GL_VERTEX_ARRAY);
1041   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1042   glVertexPointer(2, GL_FLOAT, 0, &points[0]);
1043   glTexCoordPointer(2, GL_FLOAT, 0, &texCoord[0]);
1044   glDrawArrays(GL_QUADS, 0, 4);
1045   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1046   glDisableClientState(GL_VERTEX_ARRAY);
1047 
1048 //  this->Storage->Texture->PostRender(this->Renderer);
1049   glDisable(GL_TEXTURE_2D);
1050   glDeleteTextures(1, &index);
1051 
1052   vtkOpenGLCheckErrorMacro("failed after DrawImage");
1053 }
1054 
1055 //-----------------------------------------------------------------------------
SetColor4(unsigned char * color)1056 void vtkOpenGLContextDevice2D::SetColor4(unsigned char *color)
1057 {
1058   glColor4ubv(color);
1059 }
1060 
1061 //-----------------------------------------------------------------------------
SetColor(unsigned char * color)1062 void vtkOpenGLContextDevice2D::SetColor(unsigned char *color)
1063 {
1064   glColor3ubv(color);
1065 }
1066 
1067 //-----------------------------------------------------------------------------
SetTexture(vtkImageData * image,int properties)1068 void vtkOpenGLContextDevice2D::SetTexture(vtkImageData* image, int properties)
1069 {
1070   if (image == NULL)
1071     {
1072     if (this->Storage->Texture)
1073       {
1074       this->Storage->Texture->Delete();
1075       this->Storage->Texture = 0;
1076       }
1077     return;
1078     }
1079   if (this->Storage->Texture == NULL)
1080     {
1081     this->Storage->Texture = vtkTexture::New();
1082     }
1083   this->Storage->Texture->SetInputData(image);
1084   this->Storage->TextureProperties = properties;
1085   this->Storage->Texture->SetRepeat(properties & vtkContextDevice2D::Repeat);
1086   this->Storage->Texture->SetInterpolate(properties & vtkContextDevice2D::Linear);
1087   this->Storage->Texture->EdgeClampOn();
1088 }
1089 
1090 //-----------------------------------------------------------------------------
SetPointSize(float size)1091 void vtkOpenGLContextDevice2D::SetPointSize(float size)
1092 {
1093   glPointSize(size);
1094 }
1095 
1096 //-----------------------------------------------------------------------------
SetLineWidth(float width)1097 void vtkOpenGLContextDevice2D::SetLineWidth(float width)
1098 {
1099   glLineWidth(width);
1100 }
1101 
1102 //-----------------------------------------------------------------------------
SetLineType(int type)1103 void vtkOpenGLContextDevice2D::SetLineType(int type)
1104 {
1105   if (type == vtkPen::SOLID_LINE)
1106     {
1107     glDisable(GL_LINE_STIPPLE);
1108     }
1109   else
1110     {
1111     glEnable(GL_LINE_STIPPLE);
1112     }
1113   GLushort pattern = 0x0000;
1114   switch (type)
1115     {
1116     case vtkPen::NO_PEN:
1117       pattern = 0x0000;
1118       break;
1119     case vtkPen::DASH_LINE:
1120       pattern = 0x00FF;
1121       break;
1122     case vtkPen::DOT_LINE:
1123       pattern = 0x0101;
1124       break;
1125     case vtkPen::DASH_DOT_LINE:
1126       pattern = 0x0C0F;
1127       break;
1128     case vtkPen::DASH_DOT_DOT_LINE:
1129       pattern = 0x1C47;
1130       break;
1131     default:
1132       pattern = 0x0000;
1133     }
1134   glLineStipple(1, pattern);
1135 }
1136 
1137 //-----------------------------------------------------------------------------
MultiplyMatrix(vtkMatrix3x3 * m)1138 void vtkOpenGLContextDevice2D::MultiplyMatrix(vtkMatrix3x3 *m)
1139 {
1140   // We must construct a 4x4 matrix from the 3x3 matrix for OpenGL
1141   double *M = m->GetData();
1142   double matrix[16];
1143 
1144   // Convert from row major (C++ two dimensional arrays) to OpenGL
1145   matrix[0] = M[0];
1146   matrix[1] = M[3];
1147   matrix[2] = 0.0;
1148   matrix[3] = M[6];
1149 
1150   matrix[4] = M[1];
1151   matrix[5] = M[4];
1152   matrix[6] = 0.0;
1153   matrix[7] = M[7];
1154 
1155   matrix[8] = 0.0;
1156   matrix[9] = 0.0;
1157   matrix[10] = 1.0;
1158   matrix[11] = 0.0;
1159 
1160   matrix[12] = M[2];
1161   matrix[13] = M[5];
1162   matrix[14] = 0.0;
1163   matrix[15] = M[8];
1164 
1165   glMultMatrixd(matrix);
1166 }
1167 
1168 //-----------------------------------------------------------------------------
SetMatrix(vtkMatrix3x3 * m)1169 void vtkOpenGLContextDevice2D::SetMatrix(vtkMatrix3x3 *m)
1170 {
1171   // We must construct a 4x4 matrix from the 3x3 matrix for OpenGL
1172   double *M = m->GetData();
1173   double matrix[16];
1174 
1175   // Convert from row major (C++ two dimensional arrays) to OpenGL
1176   matrix[0] = M[0];
1177   matrix[1] = M[3];
1178   matrix[2] = 0.0;
1179   matrix[3] = M[6];
1180 
1181   matrix[4] = M[1];
1182   matrix[5] = M[4];
1183   matrix[6] = 0.0;
1184   matrix[7] = M[7];
1185 
1186   matrix[8] = 0.0;
1187   matrix[9] = 0.0;
1188   matrix[10] = 1.0;
1189   matrix[11] = 0.0;
1190 
1191   matrix[12] = M[2];
1192   matrix[13] = M[5];
1193   matrix[14] = 0.0;
1194   matrix[15] = M[8];
1195 
1196   glLoadMatrixd(matrix);
1197 }
1198 
1199 //-----------------------------------------------------------------------------
GetMatrix(vtkMatrix3x3 * m)1200 void vtkOpenGLContextDevice2D::GetMatrix(vtkMatrix3x3 *m)
1201 {
1202   assert("pre: non_null" && m != NULL);
1203   // We must construct a 4x4 matrix from the 3x3 matrix for OpenGL
1204   double *M = m->GetData();
1205   double matrix[16];
1206   glGetDoublev(GL_MODELVIEW_MATRIX, matrix);
1207 
1208   // Convert from row major (C++ two dimensional arrays) to OpenGL
1209   M[0] = matrix[0];
1210   M[1] = matrix[4];
1211   M[2] = matrix[12];
1212   M[3] = matrix[1];
1213   M[4] = matrix[5];
1214   M[5] = matrix[13];
1215   M[6] = matrix[3];
1216   M[7] = matrix[7];
1217   M[8] = matrix[15];
1218 
1219   m->Modified();
1220 }
1221 
1222 //-----------------------------------------------------------------------------
PushMatrix()1223 void vtkOpenGLContextDevice2D::PushMatrix()
1224 {
1225   vtkOpenGLClearErrorMacro();
1226   glMatrixMode( GL_MODELVIEW );
1227   glPushMatrix();
1228   vtkOpenGLCheckErrorMacro("failed after PushMatrix");
1229 }
1230 
1231 //-----------------------------------------------------------------------------
PopMatrix()1232 void vtkOpenGLContextDevice2D::PopMatrix()
1233 {
1234   vtkOpenGLClearErrorMacro();
1235   glMatrixMode( GL_MODELVIEW );
1236   glPopMatrix();
1237   vtkOpenGLCheckErrorMacro("failed after PopMatrix");
1238 }
1239 
1240 //-----------------------------------------------------------------------------
SetClipping(int * dim)1241 void vtkOpenGLContextDevice2D::SetClipping(int *dim)
1242 {
1243   // Check the bounds, and clamp if necessary
1244   GLint vp[4] = { this->Storage->Offset.GetX(), this->Storage->Offset.GetY(),
1245     this->Storage->Dim.GetX(),this->Storage->Dim.GetY()};
1246 
1247   if (dim[0] > 0 && dim[0] < vp[2] )
1248     {
1249     vp[0] += dim[0];
1250     }
1251   if (dim[1] > 0 && dim[1] < vp[3])
1252     {
1253     vp[1] += dim[1];
1254     }
1255   if (dim[2] > 0 && dim[2] < vp[2])
1256     {
1257     vp[2] = dim[2];
1258     }
1259   if (dim[3] > 0 && dim[3] < vp[3])
1260     {
1261     vp[3] = dim[3];
1262     }
1263 
1264   glScissor(vp[0], vp[1], vp[2], vp[3]);
1265 }
1266 
1267 //-----------------------------------------------------------------------------
EnableClipping(bool enable)1268 void vtkOpenGLContextDevice2D::EnableClipping(bool enable)
1269 {
1270   if (enable)
1271     {
1272     glEnable(GL_SCISSOR_TEST);
1273     }
1274   else
1275     {
1276     glDisable(GL_SCISSOR_TEST);
1277     }
1278 }
1279 
1280 //-----------------------------------------------------------------------------
SetStringRendererToFreeType()1281 bool vtkOpenGLContextDevice2D::SetStringRendererToFreeType()
1282 {
1283   // FreeType is the only choice - nothing to do here
1284   return true;
1285 }
1286 
1287 //-----------------------------------------------------------------------------
SetStringRendererToQt()1288 bool vtkOpenGLContextDevice2D::SetStringRendererToQt()
1289 {
1290   // The Qt based strategy is not available
1291   return false;
1292 }
1293 
1294 //----------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * window)1295 void vtkOpenGLContextDevice2D::ReleaseGraphicsResources(vtkWindow *window)
1296 {
1297   if (this->Storage->Texture)
1298     {
1299     this->Storage->Texture->ReleaseGraphicsResources(window);
1300     }
1301   if (this->Storage->SpriteTexture)
1302     {
1303     this->Storage->SpriteTexture->ReleaseGraphicsResources(window);
1304     }
1305   this->Storage->TextTextureCache.ReleaseGraphicsResources(window);
1306   this->Storage->MathTextTextureCache.ReleaseGraphicsResources(window);
1307 }
1308 
1309 //----------------------------------------------------------------------------
HasGLSL()1310 bool vtkOpenGLContextDevice2D::HasGLSL()
1311 {
1312   return true;
1313 }
1314 
1315 //-----------------------------------------------------------------------------
GetMarker(int shape,int size,bool highlight)1316 vtkImageData *vtkOpenGLContextDevice2D::GetMarker(int shape, int size,
1317                                                   bool highlight)
1318 {
1319   // Generate the cache key for this marker
1320   vtkTypeUInt64 key = highlight ? (1U << 31) : 0U;
1321   key |= static_cast<vtkTypeUInt16>(shape);
1322   key <<= 32;
1323   key |= static_cast<vtkTypeUInt32>(size);
1324 
1325   // Try to find the marker in the cache
1326   std::list<vtkMarkerCacheObject>::iterator match =
1327       std::find(this->MarkerCache.begin(), this->MarkerCache.end(), key);
1328 
1329   // Was it in the cache?
1330   if (match != this->MarkerCache.end())
1331     {
1332     // Yep -- move it to the front and return the data.
1333     if (match == this->MarkerCache.begin())
1334       {
1335       return match->Value;
1336       }
1337     else
1338       {
1339       vtkMarkerCacheObject result = *match;
1340       this->MarkerCache.erase(match);
1341       this->MarkerCache.push_front(result);
1342       return result.Value;
1343       }
1344     }
1345 
1346   // Nope -- we'll need to generate it. Create the image data:
1347   vtkMarkerCacheObject result;
1348   result.Key = key;
1349   result.Value = this->GenerateMarker(shape, size, highlight);
1350 
1351   // If there was an issue generating the marker, just return NULL.
1352   if (!result.Value)
1353     {
1354     vtkErrorMacro(<<"Error generating marker: shape,size: "
1355                   << shape << "," << size)
1356     return NULL;
1357     }
1358 
1359   // Check the current cache size.
1360   while (this->MarkerCache.size() >
1361          static_cast<size_t>(this->MaximumMarkerCacheSize - 1) &&
1362          !this->MarkerCache.empty())
1363     {
1364     this->MarkerCache.back().Value->Delete();
1365     this->MarkerCache.pop_back();
1366     }
1367 
1368    // Add to the cache
1369    this->MarkerCache.push_front(result);
1370    return result.Value;
1371 }
1372 
1373 //-----------------------------------------------------------------------------
GenerateMarker(int shape,int width,bool highlight)1374 vtkImageData *vtkOpenGLContextDevice2D::GenerateMarker(int shape, int width,
1375                                                        bool highlight)
1376 {
1377   // Set up the image data, if highlight then the mark shape is different
1378   vtkImageData *result = vtkImageData::New();
1379 
1380   result->SetExtent(0, width - 1, 0, width - 1, 0, 0);
1381   result->AllocateScalars(VTK_UNSIGNED_CHAR, 4);
1382 
1383   unsigned char* image =
1384       static_cast<unsigned char*>(result->GetScalarPointer());
1385   memset(image, 0, width * width * 4);
1386 
1387   // Generate the marker image at the required size
1388   switch (shape)
1389     {
1390     case VTK_MARKER_CROSS:
1391       {
1392       int center = (width + 1) / 2;
1393       for (int i = 0; i < center; ++i)
1394         {
1395         int j = width - i - 1;
1396         memset(image + (4 * (width * i + i)), 255, 4);
1397         memset(image + (4 * (width * i + j)), 255, 4);
1398         memset(image + (4 * (width * j + i)), 255, 4);
1399         memset(image + (4 * (width * j + j)), 255, 4);
1400         if (highlight)
1401           {
1402           memset(image + (4 * (width * (j-1) + (i))), 255, 4);
1403           memset(image + (4 * (width * (i+1) + (i))), 255, 4);
1404           memset(image + (4 * (width * (i) + (i+1))), 255, 4);
1405           memset(image + (4 * (width * (i) + (j-1))), 255, 4);
1406           memset(image + (4 * (width * (i+1) + (j))), 255, 4);
1407           memset(image + (4 * (width * (j-1) + (j))), 255, 4);
1408           memset(image + (4 * (width * (j) + (j-1))), 255, 4);
1409           memset(image + (4 * (width * (j) + (i+1))), 255, 4);
1410           }
1411         }
1412       break;
1413       }
1414     default: // Maintaining old behavior, which produces plus for unknown shape
1415       vtkWarningMacro(<<"Invalid marker shape: " << shape);
1416     case VTK_MARKER_PLUS:
1417       {
1418       int center = (width + 1) / 2;
1419       for (int i = 0; i < center; ++i)
1420         {
1421         int j = width - i - 1;
1422         int c = center - 1;
1423         memset(image + (4 * (width * c + i)), 255, 4);
1424         memset(image + (4 * (width * c + j)), 255, 4);
1425         memset(image + (4 * (width * i + c)), 255, 4);
1426         memset(image + (4 * (width * j + c)), 255, 4);
1427         if (highlight)
1428           {
1429           memset(image + (4 * (width * (c - 1) + i)), 255, 4);
1430           memset(image + (4 * (width * (c + 1) + i)), 255, 4);
1431           memset(image + (4 * (width * (c - 1) + j)), 255, 4);
1432           memset(image + (4 * (width * (c + 1) + j)), 255, 4);
1433           memset(image + (4 * (width * i + (c - 1))), 255, 4);
1434           memset(image + (4 * (width * i + (c + 1))), 255, 4);
1435           memset(image + (4 * (width * j + (c - 1))), 255, 4);
1436           memset(image + (4 * (width * j + (c + 1))), 255, 4);
1437           }
1438         }
1439       break;
1440       }
1441     case VTK_MARKER_SQUARE:
1442       {
1443       memset(image, 255, width * width * 4);
1444       break;
1445       }
1446     case VTK_MARKER_CIRCLE:
1447       {
1448       double r = width/2.0;
1449       double r2 = r * r;
1450       for (int i = 0; i < width; ++i)
1451         {
1452         double dx2 = (i - r) * (i - r);
1453         for (int j = 0; j < width; ++j)
1454           {
1455           double dy2 = (j - r) * (j - r);
1456           if ((dx2 + dy2) < r2)
1457             {
1458             memset(image + (4 * width * i) + (4 * j), 255, 4);
1459             }
1460           }
1461         }
1462       break;
1463       }
1464     case VTK_MARKER_DIAMOND:
1465       {
1466       int r = width/2;
1467       for (int i = 0; i < width; ++i)
1468         {
1469         int dx = abs(i - r);
1470         for (int j = 0; j < width; ++j)
1471           {
1472           int dy = abs(j - r);
1473           if (r - dx >= dy)
1474             {
1475             memset(image + (4 * width * i) + (4 * j), 255, 4);
1476             }
1477           }
1478         }
1479       break;
1480       }
1481     }
1482   return result;
1483 }
1484 
1485 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1486 void vtkOpenGLContextDevice2D::PrintSelf(ostream &os, vtkIndent indent)
1487 {
1488   this->Superclass::PrintSelf(os, indent);
1489   os << indent << "Renderer: ";
1490   if (this->Renderer)
1491   {
1492     os << endl;
1493     this->Renderer->PrintSelf(os, indent.GetNextIndent());
1494   }
1495   else
1496     {
1497     os << "(none)" << endl;
1498     }
1499   os << indent << "Text Renderer: ";
1500   if (this->Renderer)
1501   {
1502     os << endl;
1503     this->TextRenderer->PrintSelf(os, indent.GetNextIndent());
1504   }
1505   else
1506     {
1507     os << "(none)" << endl;
1508     }
1509   os << indent << "MaximumMarkerCacheSize: "
1510      << this->MaximumMarkerCacheSize << endl;
1511   os << indent << "MarkerCache: " << this->MarkerCache.size()
1512      << " entries." << endl;
1513 }
1514