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