1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //
6 //  This software is distributed WITHOUT ANY WARRANTY; without even
7 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 //  PURPOSE.  See the above copyright notice for more information.
9 //============================================================================
10 
11 #include <vtkm/rendering/Canvas.h>
12 
13 #include <vtkm/cont/ArrayHandleCounting.h>
14 #include <vtkm/cont/DataSetBuilderUniform.h>
15 #include <vtkm/cont/TryExecute.h>
16 #include <vtkm/io/DecodePNG.h>
17 #include <vtkm/io/EncodePNG.h>
18 #include <vtkm/io/FileUtils.h>
19 #include <vtkm/io/ImageUtils.h>
20 #include <vtkm/rendering/BitmapFontFactory.h>
21 #include <vtkm/rendering/LineRenderer.h>
22 #include <vtkm/rendering/TextRenderer.h>
23 #include <vtkm/rendering/WorldAnnotator.h>
24 #include <vtkm/worklet/DispatcherMapField.h>
25 #include <vtkm/worklet/WorkletMapField.h>
26 
27 #include <fstream>
28 #include <iostream>
29 
30 namespace vtkm
31 {
32 namespace rendering
33 {
34 namespace internal
35 {
36 
37 struct ClearBuffers : public vtkm::worklet::WorkletMapField
38 {
39   using ControlSignature = void(FieldOut, FieldOut);
40   using ExecutionSignature = void(_1, _2);
41 
42   VTKM_CONT
ClearBuffersvtkm::rendering::internal::ClearBuffers43   ClearBuffers() {}
44 
45   VTKM_EXEC
operator ()vtkm::rendering::internal::ClearBuffers46   void operator()(vtkm::Vec4f_32& color, vtkm::Float32& depth) const
47   {
48     color[0] = 0.f;
49     color[1] = 0.f;
50     color[2] = 0.f;
51     color[3] = 0.f;
52     // The depth is set to slightly larger than 1.0f, ensuring this color value always fails a
53     // depth check
54     depth = VTKM_DEFAULT_CANVAS_DEPTH;
55   }
56 }; // struct ClearBuffers
57 
58 struct BlendBackground : public vtkm::worklet::WorkletMapField
59 {
60   vtkm::Vec4f_32 BackgroundColor;
61 
62   VTKM_CONT
BlendBackgroundvtkm::rendering::internal::BlendBackground63   BlendBackground(const vtkm::Vec4f_32& backgroundColor)
64     : BackgroundColor(backgroundColor)
65   {
66   }
67 
68   using ControlSignature = void(FieldInOut);
69   using ExecutionSignature = void(_1);
70 
operator ()vtkm::rendering::internal::BlendBackground71   VTKM_EXEC void operator()(vtkm::Vec4f_32& color) const
72   {
73     if (color[3] >= 1.f)
74       return;
75 
76     vtkm::Float32 alpha = BackgroundColor[3] * (1.f - color[3]);
77     color[0] = color[0] + BackgroundColor[0] * alpha;
78     color[1] = color[1] + BackgroundColor[1] * alpha;
79     color[2] = color[2] + BackgroundColor[2] * alpha;
80     color[3] = alpha + color[3];
81   }
82 }; // struct BlendBackground
83 
84 struct DrawColorSwatch : public vtkm::worklet::WorkletMapField
85 {
86   using ControlSignature = void(FieldIn, WholeArrayInOut);
87   using ExecutionSignature = void(_1, _2);
88 
89   VTKM_CONT
DrawColorSwatchvtkm::rendering::internal::DrawColorSwatch90   DrawColorSwatch(vtkm::Id2 dims, vtkm::Id2 xBounds, vtkm::Id2 yBounds, const vtkm::Vec4f_32 color)
91     : Color(color)
92   {
93     ImageWidth = dims[0];
94     ImageHeight = dims[1];
95     SwatchBottomLeft[0] = xBounds[0];
96     SwatchBottomLeft[1] = yBounds[0];
97     SwatchWidth = xBounds[1] - xBounds[0];
98     SwatchHeight = yBounds[1] - yBounds[0];
99   }
100 
101   template <typename FrameBuffer>
operator ()vtkm::rendering::internal::DrawColorSwatch102   VTKM_EXEC void operator()(const vtkm::Id& index, FrameBuffer& frameBuffer) const
103   {
104     // local bar coord
105     vtkm::Id x = index % SwatchWidth;
106     vtkm::Id y = index / SwatchWidth;
107 
108     // offset to global image coord
109     x += SwatchBottomLeft[0];
110     y += SwatchBottomLeft[1];
111 
112     vtkm::Id offset = y * ImageWidth + x;
113     frameBuffer.Set(offset, Color);
114   }
115 
116   vtkm::Id ImageWidth;
117   vtkm::Id ImageHeight;
118   vtkm::Id2 SwatchBottomLeft;
119   vtkm::Id SwatchWidth;
120   vtkm::Id SwatchHeight;
121   const vtkm::Vec4f_32 Color;
122 }; // struct DrawColorSwatch
123 
124 struct DrawColorBar : public vtkm::worklet::WorkletMapField
125 {
126   using ControlSignature = void(FieldIn, WholeArrayInOut, WholeArrayIn);
127   using ExecutionSignature = void(_1, _2, _3);
128 
129   VTKM_CONT
DrawColorBarvtkm::rendering::internal::DrawColorBar130   DrawColorBar(vtkm::Id2 dims, vtkm::Id2 xBounds, vtkm::Id2 yBounds, bool horizontal)
131     : Horizontal(horizontal)
132   {
133     ImageWidth = dims[0];
134     ImageHeight = dims[1];
135     BarBottomLeft[0] = xBounds[0];
136     BarBottomLeft[1] = yBounds[0];
137     BarWidth = xBounds[1] - xBounds[0];
138     BarHeight = yBounds[1] - yBounds[0];
139   }
140 
141   template <typename FrameBuffer, typename ColorMap>
operator ()vtkm::rendering::internal::DrawColorBar142   VTKM_EXEC void operator()(const vtkm::Id& index,
143                             FrameBuffer& frameBuffer,
144                             const ColorMap& colorMap) const
145   {
146     // local bar coord
147     vtkm::Id x = index % BarWidth;
148     vtkm::Id y = index / BarWidth;
149     vtkm::Id sample = Horizontal ? x : y;
150 
151 
152     const vtkm::Vec4ui_8 color = colorMap.Get(sample);
153 
154     vtkm::Float32 normalizedHeight = Horizontal
155       ? static_cast<vtkm::Float32>(y) / static_cast<vtkm::Float32>(BarHeight)
156       : static_cast<vtkm::Float32>(x) / static_cast<vtkm::Float32>(BarWidth);
157     // offset to global image coord
158     x += BarBottomLeft[0];
159     y += BarBottomLeft[1];
160 
161     vtkm::Id offset = y * ImageWidth + x;
162     // If the colortable has alpha values, we blend each color sample with translucent white.
163     // The height of the resultant translucent bar indicates the opacity.
164 
165     constexpr vtkm::Float32 conversionToFloatSpace = (1.0f / 255.0f);
166     vtkm::Float32 alpha = color[3] * conversionToFloatSpace;
167     if (alpha < 1 && normalizedHeight <= alpha)
168     {
169       constexpr vtkm::Float32 intensity = 0.4f;
170       constexpr vtkm::Float32 inverseIntensity = (1.0f - intensity);
171       alpha *= inverseIntensity;
172       vtkm::Vec4f_32 blendedColor(1.0f * intensity + (color[0] * conversionToFloatSpace) * alpha,
173                                   1.0f * intensity + (color[1] * conversionToFloatSpace) * alpha,
174                                   1.0f * intensity + (color[2] * conversionToFloatSpace) * alpha,
175                                   1.0f);
176       frameBuffer.Set(offset, blendedColor);
177     }
178     else
179     {
180       // make sure this is opaque
181       vtkm::Vec4f_32 fColor((color[0] * conversionToFloatSpace),
182                             (color[1] * conversionToFloatSpace),
183                             (color[2] * conversionToFloatSpace),
184                             1.0f);
185       frameBuffer.Set(offset, fColor);
186     }
187   }
188 
189   vtkm::Id ImageWidth;
190   vtkm::Id ImageHeight;
191   vtkm::Id2 BarBottomLeft;
192   vtkm::Id BarWidth;
193   vtkm::Id BarHeight;
194   bool Horizontal;
195 }; // struct DrawColorBar
196 
197 } // namespace internal
198 
199 struct Canvas::CanvasInternals
200 {
201 
CanvasInternalsvtkm::rendering::Canvas::CanvasInternals202   CanvasInternals(vtkm::Id width, vtkm::Id height)
203     : Width(width)
204     , Height(height)
205   {
206     BackgroundColor.Components[0] = 0.f;
207     BackgroundColor.Components[1] = 0.f;
208     BackgroundColor.Components[2] = 0.f;
209     BackgroundColor.Components[3] = 1.f;
210 
211     ForegroundColor.Components[0] = 1.f;
212     ForegroundColor.Components[1] = 1.f;
213     ForegroundColor.Components[2] = 1.f;
214     ForegroundColor.Components[3] = 1.f;
215   }
216 
217   vtkm::Id Width;
218   vtkm::Id Height;
219   vtkm::rendering::Color BackgroundColor;
220   vtkm::rendering::Color ForegroundColor;
221   ColorBufferType ColorBuffer;
222   DepthBufferType DepthBuffer;
223   vtkm::rendering::BitmapFont Font;
224   FontTextureType FontTexture;
225   vtkm::Matrix<vtkm::Float32, 4, 4> ModelView;
226   vtkm::Matrix<vtkm::Float32, 4, 4> Projection;
227 };
228 
Canvas(vtkm::Id width,vtkm::Id height)229 Canvas::Canvas(vtkm::Id width, vtkm::Id height)
230   : Internals(new CanvasInternals(0, 0))
231 {
232   vtkm::MatrixIdentity(Internals->ModelView);
233   vtkm::MatrixIdentity(Internals->Projection);
234   this->ResizeBuffers(width, height);
235 }
236 
~Canvas()237 Canvas::~Canvas() {}
238 
NewCopy() const239 vtkm::rendering::Canvas* Canvas::NewCopy() const
240 {
241   return new vtkm::rendering::Canvas(*this);
242 }
243 
GetWidth() const244 vtkm::Id Canvas::GetWidth() const
245 {
246   return Internals->Width;
247 }
248 
GetHeight() const249 vtkm::Id Canvas::GetHeight() const
250 {
251   return Internals->Height;
252 }
253 
GetColorBuffer() const254 const Canvas::ColorBufferType& Canvas::GetColorBuffer() const
255 {
256   return Internals->ColorBuffer;
257 }
258 
GetColorBuffer()259 Canvas::ColorBufferType& Canvas::GetColorBuffer()
260 {
261   return Internals->ColorBuffer;
262 }
263 
GetDepthBuffer() const264 const Canvas::DepthBufferType& Canvas::GetDepthBuffer() const
265 {
266   return Internals->DepthBuffer;
267 }
268 
GetDepthBuffer()269 Canvas::DepthBufferType& Canvas::GetDepthBuffer()
270 {
271   return Internals->DepthBuffer;
272 }
273 
GetDataSet(const std::string & colorFieldName,const std::string & depthFieldName) const274 vtkm::cont::DataSet Canvas::GetDataSet(const std::string& colorFieldName,
275                                        const std::string& depthFieldName) const
276 {
277   vtkm::cont::DataSetBuilderUniform builder;
278   vtkm::cont::DataSet dataSet = builder.Create(vtkm::Id2(this->GetWidth(), this->GetHeight()));
279   if (!colorFieldName.empty())
280   {
281     dataSet.AddPointField(colorFieldName, this->GetColorBuffer());
282   }
283   if (!depthFieldName.empty())
284   {
285     dataSet.AddPointField(depthFieldName, this->GetDepthBuffer());
286   }
287   return dataSet;
288 }
289 
GetDataSet(const char * colorFieldName,const char * depthFieldName) const290 vtkm::cont::DataSet Canvas::GetDataSet(const char* colorFieldName, const char* depthFieldName) const
291 {
292   return this->GetDataSet((colorFieldName != nullptr) ? std::string(colorFieldName) : std::string(),
293                           (depthFieldName != nullptr) ? std::string(depthFieldName)
294                                                       : std::string());
295 }
296 
GetBackgroundColor() const297 const vtkm::rendering::Color& Canvas::GetBackgroundColor() const
298 {
299   return Internals->BackgroundColor;
300 }
301 
SetBackgroundColor(const vtkm::rendering::Color & color)302 void Canvas::SetBackgroundColor(const vtkm::rendering::Color& color)
303 {
304   Internals->BackgroundColor = color;
305 }
306 
GetForegroundColor() const307 const vtkm::rendering::Color& Canvas::GetForegroundColor() const
308 {
309   return Internals->ForegroundColor;
310 }
311 
SetForegroundColor(const vtkm::rendering::Color & color)312 void Canvas::SetForegroundColor(const vtkm::rendering::Color& color)
313 {
314   Internals->ForegroundColor = color;
315 }
316 
Clear()317 void Canvas::Clear()
318 {
319   internal::ClearBuffers worklet;
320   vtkm::worklet::DispatcherMapField<internal::ClearBuffers> dispatcher(worklet);
321   dispatcher.Invoke(this->GetColorBuffer(), this->GetDepthBuffer());
322 }
323 
BlendBackground()324 void Canvas::BlendBackground()
325 {
326   internal::BlendBackground worklet(GetBackgroundColor().Components);
327   vtkm::worklet::DispatcherMapField<internal::BlendBackground> dispatcher(worklet);
328   dispatcher.Invoke(this->GetColorBuffer());
329 }
330 
ResizeBuffers(vtkm::Id width,vtkm::Id height)331 void Canvas::ResizeBuffers(vtkm::Id width, vtkm::Id height)
332 {
333   VTKM_ASSERT(width >= 0);
334   VTKM_ASSERT(height >= 0);
335 
336   vtkm::Id numPixels = width * height;
337   if (Internals->ColorBuffer.GetNumberOfValues() != numPixels)
338   {
339     Internals->ColorBuffer.Allocate(numPixels);
340   }
341   if (Internals->DepthBuffer.GetNumberOfValues() != numPixels)
342   {
343     Internals->DepthBuffer.Allocate(numPixels);
344   }
345 
346   Internals->Width = width;
347   Internals->Height = height;
348 }
349 
AddColorSwatch(const vtkm::Vec2f_64 & point0,const vtkm::Vec2f_64 & vtkmNotUsed (point1),const vtkm::Vec2f_64 & point2,const vtkm::Vec2f_64 & vtkmNotUsed (point3),const vtkm::rendering::Color & color) const350 void Canvas::AddColorSwatch(const vtkm::Vec2f_64& point0,
351                             const vtkm::Vec2f_64& vtkmNotUsed(point1),
352                             const vtkm::Vec2f_64& point2,
353                             const vtkm::Vec2f_64& vtkmNotUsed(point3),
354                             const vtkm::rendering::Color& color) const
355 {
356   vtkm::Float64 width = static_cast<vtkm::Float64>(this->GetWidth());
357   vtkm::Float64 height = static_cast<vtkm::Float64>(this->GetHeight());
358 
359   vtkm::Id2 x, y;
360   x[0] = static_cast<vtkm::Id>(((point0[0] + 1.) / 2.) * width + .5);
361   x[1] = static_cast<vtkm::Id>(((point2[0] + 1.) / 2.) * width + .5);
362   y[0] = static_cast<vtkm::Id>(((point0[1] + 1.) / 2.) * height + .5);
363   y[1] = static_cast<vtkm::Id>(((point2[1] + 1.) / 2.) * height + .5);
364 
365   vtkm::Id2 dims(this->GetWidth(), this->GetHeight());
366 
367   vtkm::Id totalPixels = (x[1] - x[0]) * (y[1] - y[0]);
368   vtkm::cont::ArrayHandleCounting<vtkm::Id> iterator(0, 1, totalPixels);
369   vtkm::worklet::DispatcherMapField<internal::DrawColorSwatch> dispatcher(
370     internal::DrawColorSwatch(dims, x, y, color.Components));
371   dispatcher.Invoke(iterator, this->GetColorBuffer());
372 }
373 
AddColorSwatch(const vtkm::Float64 x0,const vtkm::Float64 y0,const vtkm::Float64 x1,const vtkm::Float64 y1,const vtkm::Float64 x2,const vtkm::Float64 y2,const vtkm::Float64 x3,const vtkm::Float64 y3,const vtkm::rendering::Color & color) const374 void Canvas::AddColorSwatch(const vtkm::Float64 x0,
375                             const vtkm::Float64 y0,
376                             const vtkm::Float64 x1,
377                             const vtkm::Float64 y1,
378                             const vtkm::Float64 x2,
379                             const vtkm::Float64 y2,
380                             const vtkm::Float64 x3,
381                             const vtkm::Float64 y3,
382                             const vtkm::rendering::Color& color) const
383 {
384   this->AddColorSwatch(vtkm::make_Vec(x0, y0),
385                        vtkm::make_Vec(x1, y1),
386                        vtkm::make_Vec(x2, y2),
387                        vtkm::make_Vec(x3, y3),
388                        color);
389 }
390 
AddLine(const vtkm::Vec2f_64 & point0,const vtkm::Vec2f_64 & point1,vtkm::Float32 linewidth,const vtkm::rendering::Color & color) const391 void Canvas::AddLine(const vtkm::Vec2f_64& point0,
392                      const vtkm::Vec2f_64& point1,
393                      vtkm::Float32 linewidth,
394                      const vtkm::rendering::Color& color) const
395 {
396   vtkm::rendering::Canvas* self = const_cast<vtkm::rendering::Canvas*>(this);
397   LineRenderer renderer(self, vtkm::MatrixMultiply(Internals->Projection, Internals->ModelView));
398   renderer.RenderLine(point0, point1, linewidth, color);
399 }
400 
AddLine(vtkm::Float64 x0,vtkm::Float64 y0,vtkm::Float64 x1,vtkm::Float64 y1,vtkm::Float32 linewidth,const vtkm::rendering::Color & color) const401 void Canvas::AddLine(vtkm::Float64 x0,
402                      vtkm::Float64 y0,
403                      vtkm::Float64 x1,
404                      vtkm::Float64 y1,
405                      vtkm::Float32 linewidth,
406                      const vtkm::rendering::Color& color) const
407 {
408   this->AddLine(vtkm::make_Vec(x0, y0), vtkm::make_Vec(x1, y1), linewidth, color);
409 }
410 
AddColorBar(const vtkm::Bounds & bounds,const vtkm::cont::ColorTable & colorTable,bool horizontal) const411 void Canvas::AddColorBar(const vtkm::Bounds& bounds,
412                          const vtkm::cont::ColorTable& colorTable,
413                          bool horizontal) const
414 {
415   vtkm::Float64 width = static_cast<vtkm::Float64>(this->GetWidth());
416   vtkm::Float64 height = static_cast<vtkm::Float64>(this->GetHeight());
417 
418   vtkm::Id2 x, y;
419   x[0] = static_cast<vtkm::Id>(((bounds.X.Min + 1.) / 2.) * width + .5);
420   x[1] = static_cast<vtkm::Id>(((bounds.X.Max + 1.) / 2.) * width + .5);
421   y[0] = static_cast<vtkm::Id>(((bounds.Y.Min + 1.) / 2.) * height + .5);
422   y[1] = static_cast<vtkm::Id>(((bounds.Y.Max + 1.) / 2.) * height + .5);
423   vtkm::Id barWidth = x[1] - x[0];
424   vtkm::Id barHeight = y[1] - y[0];
425 
426   vtkm::Id numSamples = horizontal ? barWidth : barHeight;
427   vtkm::cont::ArrayHandle<vtkm::Vec4ui_8> colorMap;
428 
429   {
430     vtkm::cont::ScopedRuntimeDeviceTracker tracker(vtkm::cont::DeviceAdapterTagSerial{});
431     colorTable.Sample(static_cast<vtkm::Int32>(numSamples), colorMap);
432   }
433 
434   vtkm::Id2 dims(this->GetWidth(), this->GetHeight());
435 
436   vtkm::Id totalPixels = (x[1] - x[0]) * (y[1] - y[0]);
437   vtkm::cont::ArrayHandleCounting<vtkm::Id> iterator(0, 1, totalPixels);
438   vtkm::worklet::DispatcherMapField<internal::DrawColorBar> dispatcher(
439     internal::DrawColorBar(dims, x, y, horizontal));
440   dispatcher.Invoke(iterator, this->GetColorBuffer(), colorMap);
441 }
442 
AddColorBar(vtkm::Float32 x,vtkm::Float32 y,vtkm::Float32 width,vtkm::Float32 height,const vtkm::cont::ColorTable & colorTable,bool horizontal) const443 void Canvas::AddColorBar(vtkm::Float32 x,
444                          vtkm::Float32 y,
445                          vtkm::Float32 width,
446                          vtkm::Float32 height,
447                          const vtkm::cont::ColorTable& colorTable,
448                          bool horizontal) const
449 {
450   this->AddColorBar(
451     vtkm::Bounds(vtkm::Range(x, x + width), vtkm::Range(y, y + height), vtkm::Range(0, 0)),
452     colorTable,
453     horizontal);
454 }
455 
GetScreenPoint(vtkm::Float32 x,vtkm::Float32 y,vtkm::Float32 z,const vtkm::Matrix<vtkm::Float32,4,4> & transform) const456 vtkm::Id2 Canvas::GetScreenPoint(vtkm::Float32 x,
457                                  vtkm::Float32 y,
458                                  vtkm::Float32 z,
459                                  const vtkm::Matrix<vtkm::Float32, 4, 4>& transform) const
460 {
461   vtkm::Vec4f_32 point(x, y, z, 1.0f);
462   point = vtkm::MatrixMultiply(transform, point);
463 
464   vtkm::Id2 pixelPos;
465   vtkm::Float32 width = static_cast<vtkm::Float32>(Internals->Width);
466   vtkm::Float32 height = static_cast<vtkm::Float32>(Internals->Height);
467   pixelPos[0] = static_cast<vtkm::Id>(vtkm::Round((1.0f + point[0]) * width * 0.5f + 0.5f));
468   pixelPos[1] = static_cast<vtkm::Id>(vtkm::Round((1.0f + point[1]) * height * 0.5f + 0.5f));
469   return pixelPos;
470 }
471 
AddText(const vtkm::Matrix<vtkm::Float32,4,4> & transform,vtkm::Float32 scale,const vtkm::Vec2f_32 & anchor,const vtkm::rendering::Color & color,const std::string & text,const vtkm::Float32 & depth) const472 void Canvas::AddText(const vtkm::Matrix<vtkm::Float32, 4, 4>& transform,
473                      vtkm::Float32 scale,
474                      const vtkm::Vec2f_32& anchor,
475                      const vtkm::rendering::Color& color,
476                      const std::string& text,
477                      const vtkm::Float32& depth) const
478 {
479   if (!Internals->FontTexture.IsValid())
480   {
481     if (!LoadFont())
482     {
483       return;
484     }
485   }
486 
487   vtkm::rendering::Canvas* self = const_cast<vtkm::rendering::Canvas*>(this);
488   TextRenderer fontRenderer(self, Internals->Font, Internals->FontTexture);
489   fontRenderer.RenderText(transform, scale, anchor, color, text, depth);
490 }
491 
AddText(const vtkm::Vec2f_32 & position,vtkm::Float32 scale,vtkm::Float32 angle,vtkm::Float32 windowAspect,const vtkm::Vec2f_32 & anchor,const vtkm::rendering::Color & color,const std::string & text) const492 void Canvas::AddText(const vtkm::Vec2f_32& position,
493                      vtkm::Float32 scale,
494                      vtkm::Float32 angle,
495                      vtkm::Float32 windowAspect,
496                      const vtkm::Vec2f_32& anchor,
497                      const vtkm::rendering::Color& color,
498                      const std::string& text) const
499 {
500   vtkm::Matrix<vtkm::Float32, 4, 4> translationMatrix =
501     Transform3DTranslate(position[0], position[1], 0.f);
502   vtkm::Matrix<vtkm::Float32, 4, 4> scaleMatrix = Transform3DScale(1.0f / windowAspect, 1.0f, 1.0f);
503   vtkm::Vec3f_32 rotationAxis(0.0f, 0.0f, 1.0f);
504   vtkm::Matrix<vtkm::Float32, 4, 4> rotationMatrix = Transform3DRotate(angle, rotationAxis);
505   vtkm::Matrix<vtkm::Float32, 4, 4> transform =
506     vtkm::MatrixMultiply(translationMatrix, vtkm::MatrixMultiply(scaleMatrix, rotationMatrix));
507 
508   this->AddText(transform, scale, anchor, color, text, 0.f);
509 }
510 
AddText(vtkm::Float32 x,vtkm::Float32 y,vtkm::Float32 scale,vtkm::Float32 angle,vtkm::Float32 windowAspect,vtkm::Float32 anchorX,vtkm::Float32 anchorY,const vtkm::rendering::Color & color,const std::string & text) const511 void Canvas::AddText(vtkm::Float32 x,
512                      vtkm::Float32 y,
513                      vtkm::Float32 scale,
514                      vtkm::Float32 angle,
515                      vtkm::Float32 windowAspect,
516                      vtkm::Float32 anchorX,
517                      vtkm::Float32 anchorY,
518                      const vtkm::rendering::Color& color,
519                      const std::string& text) const
520 {
521   this->AddText(vtkm::make_Vec(x, y),
522                 scale,
523                 angle,
524                 windowAspect,
525                 vtkm::make_Vec(anchorX, anchorY),
526                 color,
527                 text);
528 }
529 
LoadFont() const530 bool Canvas::LoadFont() const
531 {
532   Internals->Font = BitmapFontFactory::CreateLiberation2Sans();
533   const std::vector<unsigned char>& rawPNG = Internals->Font.GetRawImageData();
534   std::vector<unsigned char> rgba;
535   unsigned long textureWidth, textureHeight;
536   auto error = io::DecodePNG(rgba, textureWidth, textureHeight, &rawPNG[0], rawPNG.size());
537   if (error != 0)
538   {
539     return false;
540   }
541   vtkm::Id numValues = static_cast<vtkm::Id>(textureWidth * textureHeight);
542   vtkm::cont::ArrayHandle<UInt8> alpha;
543   alpha.Allocate(numValues);
544   auto alphaPortal = alpha.WritePortal();
545   for (vtkm::Id i = 0; i < numValues; ++i)
546   {
547     alphaPortal.Set(i, rgba[static_cast<std::size_t>(i * 4 + 3)]);
548   }
549   Internals->FontTexture = FontTextureType(vtkm::Id(textureWidth), vtkm::Id(textureHeight), alpha);
550   Internals->FontTexture.SetFilterMode(TextureFilterMode::Linear);
551   Internals->FontTexture.SetWrapMode(TextureWrapMode::Clamp);
552   return true;
553 }
554 
GetModelView() const555 const vtkm::Matrix<vtkm::Float32, 4, 4>& Canvas::GetModelView() const
556 {
557   return Internals->ModelView;
558 }
559 
GetProjection() const560 const vtkm::Matrix<vtkm::Float32, 4, 4>& Canvas::GetProjection() const
561 {
562   return Internals->Projection;
563 }
564 
SetViewToWorldSpace(const vtkm::rendering::Camera & camera,bool vtkmNotUsed (clip))565 void Canvas::SetViewToWorldSpace(const vtkm::rendering::Camera& camera, bool vtkmNotUsed(clip))
566 {
567   Internals->ModelView = camera.CreateViewMatrix();
568   Internals->Projection = camera.CreateProjectionMatrix(GetWidth(), GetHeight());
569 }
570 
SetViewToScreenSpace(const vtkm::rendering::Camera & vtkmNotUsed (camera),bool vtkmNotUsed (clip))571 void Canvas::SetViewToScreenSpace(const vtkm::rendering::Camera& vtkmNotUsed(camera),
572                                   bool vtkmNotUsed(clip))
573 {
574   vtkm::MatrixIdentity(Internals->ModelView);
575   vtkm::MatrixIdentity(Internals->Projection);
576   Internals->Projection[2][2] = -1.0f;
577 }
578 
SaveAs(const std::string & fileName) const579 void Canvas::SaveAs(const std::string& fileName) const
580 {
581   this->RefreshColorBuffer();
582   ColorBufferType::ReadPortalType colorPortal = GetColorBuffer().ReadPortal();
583   vtkm::Id width = GetWidth();
584   vtkm::Id height = GetHeight();
585 
586   if (vtkm::io::EndsWith(fileName, ".png"))
587   {
588     std::vector<unsigned char> img(static_cast<size_t>(4 * width * height));
589     for (vtkm::Id yIndex = height - 1; yIndex >= 0; yIndex--)
590     {
591       for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
592       {
593         vtkm::Vec4f_32 tuple = colorPortal.Get(yIndex * width + xIndex);
594         // y = 0 is the top of a .png file.
595         size_t idx = static_cast<size_t>(4 * width * (height - 1 - yIndex) + 4 * xIndex);
596         img[idx + 0] = (unsigned char)(tuple[0] * 255);
597         img[idx + 1] = (unsigned char)(tuple[1] * 255);
598         img[idx + 2] = (unsigned char)(tuple[2] * 255);
599         img[idx + 3] = (unsigned char)(tuple[3] * 255);
600       }
601     }
602 
603     vtkm::io::SavePNG(
604       fileName, img, static_cast<unsigned long>(width), static_cast<unsigned long>(height));
605     return;
606   }
607 
608   std::ofstream of(fileName.c_str(), std::ios_base::binary | std::ios_base::out);
609   of << "P6" << std::endl << width << " " << height << std::endl << 255 << std::endl;
610   for (vtkm::Id yIndex = height - 1; yIndex >= 0; yIndex--)
611   {
612     for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
613     {
614       vtkm::Vec4f_32 tuple = colorPortal.Get(yIndex * width + xIndex);
615       of << (unsigned char)(tuple[0] * 255);
616       of << (unsigned char)(tuple[1] * 255);
617       of << (unsigned char)(tuple[2] * 255);
618     }
619   }
620   of.close();
621 }
622 
CreateWorldAnnotator() const623 vtkm::rendering::WorldAnnotator* Canvas::CreateWorldAnnotator() const
624 {
625   return new vtkm::rendering::WorldAnnotator(this);
626 }
627 }
628 } // vtkm::rendering
629