1b541bdd37
There were some places in the rendering code where floating point exceptions (FPE) could happen under certain circumstances. Often we do not care about invalid floating point operation in rendering as they often occur in degenerate cases that don't contribute anyway. However, simulations that might include VTK-m might turn on FPE to check their own operations. In such cases, we don't want errant rendering arithmetic causing an exception and bringing down the whole code. Thus, we turn on FPE in some of our test platforms and avoid such operations in general.
604 lines
19 KiB
C++
604 lines
19 KiB
C++
//============================================================================
|
|
// Copyright (c) Kitware, Inc.
|
|
// All rights reserved.
|
|
// See LICENSE.txt for details.
|
|
//
|
|
// This software is distributed WITHOUT ANY WARRANTY; without even
|
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
// PURPOSE. See the above copyright notice for more information.
|
|
//============================================================================
|
|
|
|
#ifndef vtk_m_rendering_Wireframer_h
|
|
#define vtk_m_rendering_Wireframer_h
|
|
|
|
#include <vtkm/Assert.h>
|
|
#include <vtkm/Math.h>
|
|
#include <vtkm/Swap.h>
|
|
#include <vtkm/Types.h>
|
|
#include <vtkm/VectorAnalysis.h>
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
#include <vtkm/cont/AtomicArray.h>
|
|
#include <vtkm/rendering/MatrixHelpers.h>
|
|
#include <vtkm/rendering/Triangulator.h>
|
|
#include <vtkm/worklet/DispatcherMapField.h>
|
|
#include <vtkm/worklet/WorkletMapField.h>
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace rendering
|
|
{
|
|
namespace
|
|
{
|
|
|
|
using ColorMapHandle = vtkm::cont::ArrayHandle<vtkm::Vec4f_32>;
|
|
using IndicesHandle = vtkm::cont::ArrayHandle<vtkm::Id2>;
|
|
using PackedFrameBufferHandle = vtkm::cont::ArrayHandle<vtkm::Int64>;
|
|
|
|
// Depth value of 1.0f
|
|
const vtkm::Int64 ClearDepth = 0x3F800000;
|
|
// Packed frame buffer value with color set as black and depth as 1.0f
|
|
const vtkm::Int64 ClearValue = 0x3F800000000000FF;
|
|
|
|
VTKM_EXEC_CONT
|
|
vtkm::Float32 IntegerPart(vtkm::Float32 x)
|
|
{
|
|
return vtkm::Floor(x);
|
|
}
|
|
|
|
VTKM_EXEC_CONT
|
|
vtkm::Float32 FractionalPart(vtkm::Float32 x)
|
|
{
|
|
return x - vtkm::Floor(x);
|
|
}
|
|
|
|
VTKM_EXEC_CONT
|
|
vtkm::Float32 ReverseFractionalPart(vtkm::Float32 x)
|
|
{
|
|
return 1.0f - FractionalPart(x);
|
|
}
|
|
|
|
VTKM_EXEC_CONT
|
|
vtkm::UInt32 ScaleColorComponent(vtkm::Float32 c)
|
|
{
|
|
vtkm::Int32 t = vtkm::Int32(c * 256.0f);
|
|
return vtkm::UInt32(t < 0 ? 0 : (t > 255 ? 255 : t));
|
|
}
|
|
|
|
VTKM_EXEC_CONT
|
|
vtkm::UInt32 PackColor(vtkm::Float32 r, vtkm::Float32 g, vtkm::Float32 b, vtkm::Float32 a);
|
|
|
|
VTKM_EXEC_CONT
|
|
vtkm::UInt32 PackColor(const vtkm::Vec4f_32& color)
|
|
{
|
|
return PackColor(color[0], color[1], color[2], color[3]);
|
|
}
|
|
|
|
VTKM_EXEC_CONT
|
|
vtkm::UInt32 PackColor(vtkm::Float32 r, vtkm::Float32 g, vtkm::Float32 b, vtkm::Float32 a)
|
|
{
|
|
vtkm::UInt32 packed = (ScaleColorComponent(r) << 24);
|
|
packed |= (ScaleColorComponent(g) << 16);
|
|
packed |= (ScaleColorComponent(b) << 8);
|
|
packed |= ScaleColorComponent(a);
|
|
return packed;
|
|
}
|
|
|
|
VTKM_EXEC_CONT
|
|
void UnpackColor(vtkm::UInt32 color,
|
|
vtkm::Float32& r,
|
|
vtkm::Float32& g,
|
|
vtkm::Float32& b,
|
|
vtkm::Float32& a);
|
|
|
|
VTKM_EXEC_CONT
|
|
void UnpackColor(vtkm::UInt32 packedColor, vtkm::Vec4f_32& color)
|
|
{
|
|
UnpackColor(packedColor, color[0], color[1], color[2], color[3]);
|
|
}
|
|
|
|
VTKM_EXEC_CONT
|
|
void UnpackColor(vtkm::UInt32 color,
|
|
vtkm::Float32& r,
|
|
vtkm::Float32& g,
|
|
vtkm::Float32& b,
|
|
vtkm::Float32& a)
|
|
{
|
|
r = vtkm::Float32((color & 0xFF000000) >> 24) / 255.0f;
|
|
g = vtkm::Float32((color & 0x00FF0000) >> 16) / 255.0f;
|
|
b = vtkm::Float32((color & 0x0000FF00) >> 8) / 255.0f;
|
|
a = vtkm::Float32((color & 0x000000FF)) / 255.0f;
|
|
}
|
|
|
|
union PackedValue {
|
|
struct PackedFloats
|
|
{
|
|
vtkm::Float32 Color;
|
|
vtkm::Float32 Depth;
|
|
} Floats;
|
|
struct PackedInts
|
|
{
|
|
vtkm::UInt32 Color;
|
|
vtkm::UInt32 Depth;
|
|
} Ints;
|
|
vtkm::Int64 Raw;
|
|
}; // union PackedValue
|
|
|
|
struct CopyIntoFrameBuffer : public vtkm::worklet::WorkletMapField
|
|
{
|
|
using ControlSignature = void(FieldIn, FieldIn, FieldOut);
|
|
using ExecutionSignature = void(_1, _2, _3);
|
|
|
|
VTKM_CONT
|
|
CopyIntoFrameBuffer() {}
|
|
|
|
VTKM_EXEC
|
|
void operator()(const vtkm::Vec4f_32& color,
|
|
const vtkm::Float32& depth,
|
|
vtkm::Int64& outValue) const
|
|
{
|
|
PackedValue packed;
|
|
packed.Ints.Color = PackColor(color);
|
|
packed.Floats.Depth = depth;
|
|
outValue = packed.Raw;
|
|
}
|
|
}; //struct CopyIntoFrameBuffer
|
|
|
|
template <typename DeviceTag>
|
|
class EdgePlotter : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
using AtomicPackedFrameBufferHandle = vtkm::exec::AtomicArrayExecutionObject<vtkm::Int64>;
|
|
using AtomicPackedFrameBuffer = vtkm::cont::AtomicArray<vtkm::Int64>;
|
|
|
|
using ControlSignature = void(FieldIn, WholeArrayIn, WholeArrayIn);
|
|
using ExecutionSignature = void(_1, _2, _3);
|
|
using InputDomain = _1;
|
|
|
|
VTKM_CONT
|
|
EdgePlotter(const vtkm::Matrix<vtkm::Float32, 4, 4>& worldToProjection,
|
|
vtkm::Id width,
|
|
vtkm::Id height,
|
|
vtkm::Id subsetWidth,
|
|
vtkm::Id subsetHeight,
|
|
vtkm::Id xOffset,
|
|
vtkm::Id yOffset,
|
|
bool assocPoints,
|
|
const vtkm::Range& fieldRange,
|
|
const ColorMapHandle& colorMap,
|
|
const AtomicPackedFrameBuffer& frameBuffer,
|
|
const vtkm::Range& clippingRange,
|
|
vtkm::cont::Token& token)
|
|
: WorldToProjection(worldToProjection)
|
|
, Width(width)
|
|
, Height(height)
|
|
, SubsetWidth(subsetWidth)
|
|
, SubsetHeight(subsetHeight)
|
|
, XOffset(xOffset)
|
|
, YOffset(yOffset)
|
|
, AssocPoints(assocPoints)
|
|
, ColorMap(colorMap.PrepareForInput(DeviceTag(), token))
|
|
, ColorMapSize(vtkm::Float32(colorMap.GetNumberOfValues() - 1))
|
|
, FrameBuffer(frameBuffer.PrepareForExecution(DeviceTag(), token))
|
|
, FieldMin(vtkm::Float32(fieldRange.Min))
|
|
{
|
|
vtkm::Float32 fieldLength = vtkm::Float32(fieldRange.Length());
|
|
if (fieldLength == 0.f)
|
|
{
|
|
// constant color
|
|
this->InverseFieldDelta = 0.f;
|
|
}
|
|
else
|
|
{
|
|
this->InverseFieldDelta = 1.0f / fieldLength;
|
|
}
|
|
this->Offset = vtkm::Max(0.03f / vtkm::Float32(clippingRange.Length()), 0.0001f);
|
|
}
|
|
|
|
template <typename CoordinatesPortalType, typename ScalarFieldPortalType>
|
|
VTKM_EXEC void operator()(const vtkm::Id2& edgeIndices,
|
|
const CoordinatesPortalType& coordsPortal,
|
|
const ScalarFieldPortalType& fieldPortal) const
|
|
{
|
|
vtkm::Id point1Idx = edgeIndices[0];
|
|
vtkm::Id point2Idx = edgeIndices[1];
|
|
|
|
vtkm::Vec3f_32 point1 = coordsPortal.Get(edgeIndices[0]);
|
|
vtkm::Vec3f_32 point2 = coordsPortal.Get(edgeIndices[1]);
|
|
|
|
TransformWorldToViewport(point1);
|
|
TransformWorldToViewport(point2);
|
|
|
|
vtkm::Float32 x1 = vtkm::Round(point1[0]);
|
|
vtkm::Float32 y1 = vtkm::Round(point1[1]);
|
|
vtkm::Float32 z1 = point1[2];
|
|
vtkm::Float32 x2 = vtkm::Round(point2[0]);
|
|
vtkm::Float32 y2 = vtkm::Round(point2[1]);
|
|
vtkm::Float32 z2 = point2[2];
|
|
// If the line is steep, i.e., the height is greater than the width, then
|
|
// transpose the co-ordinates to prevent "holes" in the line. This ensures
|
|
// that we pick the co-ordinate which grows at a lesser rate than the other.
|
|
bool transposed = vtkm::Abs(y2 - y1) > vtkm::Abs(x2 - x1);
|
|
if (transposed)
|
|
{
|
|
vtkm::Swap(x1, y1);
|
|
vtkm::Swap(x2, y2);
|
|
}
|
|
|
|
// Ensure we are always going from left to right
|
|
if (x1 > x2)
|
|
{
|
|
vtkm::Swap(x1, x2);
|
|
vtkm::Swap(y1, y2);
|
|
vtkm::Swap(z1, z2);
|
|
}
|
|
|
|
vtkm::Float32 dx = x2 - x1;
|
|
vtkm::Float32 dy = y2 - y1;
|
|
if (dx == 0.0)
|
|
dx = vtkm::Epsilon32(); // Avoid FPE
|
|
vtkm::Float32 gradient = dy / dx;
|
|
|
|
vtkm::Float32 xEnd = vtkm::Round(x1);
|
|
vtkm::Float32 yEnd = y1 + gradient * (xEnd - x1);
|
|
vtkm::Float32 xPxl1 = xEnd, yPxl1 = IntegerPart(yEnd);
|
|
vtkm::Float32 zPxl1 = vtkm::Lerp(z1, z2, (xPxl1 - x1) / dx);
|
|
vtkm::Float64 point1Field = fieldPortal.Get(point1Idx);
|
|
vtkm::Float64 point2Field;
|
|
if (AssocPoints)
|
|
{
|
|
point2Field = fieldPortal.Get(point2Idx);
|
|
}
|
|
else
|
|
{
|
|
// cell associated field has a solid line color
|
|
point2Field = point1Field;
|
|
}
|
|
|
|
// Plot first endpoint
|
|
vtkm::Vec4f_32 color = GetColor(point1Field);
|
|
if (transposed)
|
|
{
|
|
Plot(yPxl1, xPxl1, zPxl1, color, 1.0f);
|
|
}
|
|
else
|
|
{
|
|
Plot(xPxl1, yPxl1, zPxl1, color, 1.0f);
|
|
}
|
|
|
|
vtkm::Float32 interY = yEnd + gradient;
|
|
xEnd = vtkm::Round(x2);
|
|
yEnd = y2 + gradient * (xEnd - x2);
|
|
vtkm::Float32 xPxl2 = xEnd, yPxl2 = IntegerPart(yEnd);
|
|
vtkm::Float32 zPxl2 = vtkm::Lerp(z1, z2, (xPxl2 - x1) / dx);
|
|
|
|
// Plot second endpoint
|
|
color = GetColor(point2Field);
|
|
if (transposed)
|
|
{
|
|
Plot(yPxl2, xPxl2, zPxl2, color, 1.0f);
|
|
}
|
|
else
|
|
{
|
|
Plot(xPxl2, yPxl2, zPxl2, color, 1.0f);
|
|
}
|
|
|
|
// Plot rest of the line
|
|
if (transposed)
|
|
{
|
|
for (vtkm::Float32 x = xPxl1 + 1; x <= xPxl2 - 1; ++x)
|
|
{
|
|
vtkm::Float32 t = IntegerPart(interY);
|
|
vtkm::Float32 factor = (x - x1) / dx;
|
|
vtkm::Float32 depth = vtkm::Lerp(zPxl1, zPxl2, factor);
|
|
vtkm::Float64 fieldValue = vtkm::Lerp(point1Field, point2Field, factor);
|
|
color = GetColor(fieldValue);
|
|
Plot(t, x, depth, color, ReverseFractionalPart(interY));
|
|
Plot(t + 1, x, depth, color, FractionalPart(interY));
|
|
interY += gradient;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (vtkm::Float32 x = xPxl1 + 1; x <= xPxl2 - 1; ++x)
|
|
{
|
|
vtkm::Float32 t = IntegerPart(interY);
|
|
vtkm::Float32 factor = (x - x1) / dx;
|
|
vtkm::Float32 depth = vtkm::Lerp(zPxl1, zPxl2, factor);
|
|
vtkm::Float64 fieldValue = vtkm::Lerp(point1Field, point2Field, factor);
|
|
color = GetColor(fieldValue);
|
|
Plot(x, t, depth, color, ReverseFractionalPart(interY));
|
|
Plot(x, t + 1, depth, color, FractionalPart(interY));
|
|
interY += gradient;
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
using ColorMapPortalConst = typename ColorMapHandle::ReadPortalType;
|
|
|
|
VTKM_EXEC
|
|
void TransformWorldToViewport(vtkm::Vec3f_32& point) const
|
|
{
|
|
vtkm::Vec4f_32 temp(point[0], point[1], point[2], 1.0f);
|
|
temp = vtkm::MatrixMultiply(WorldToProjection, temp);
|
|
for (vtkm::IdComponent i = 0; i < 3; ++i)
|
|
{
|
|
point[i] = temp[i] / temp[3];
|
|
}
|
|
// Scale to canvas width and height
|
|
point[0] = (point[0] * 0.5f + 0.5f) * vtkm::Float32(SubsetWidth) + vtkm::Float32(XOffset);
|
|
point[1] = (point[1] * 0.5f + 0.5f) * vtkm::Float32(SubsetHeight) + vtkm::Float32(YOffset);
|
|
// Convert from -1/+1 to 0/+1 range
|
|
point[2] = point[2] * 0.5f + 0.5f;
|
|
// Offset the point to a bit towards the camera. This is to ensure that the front faces of
|
|
// the wireframe wins the z-depth check against the surface render, and is in addition to the
|
|
// existing camera space offset.
|
|
point[2] -= Offset;
|
|
}
|
|
|
|
VTKM_EXEC vtkm::Vec4f_32 GetColor(vtkm::Float64 fieldValue) const
|
|
{
|
|
vtkm::Int32 colorIdx = vtkm::Int32((vtkm::Float32(fieldValue) - FieldMin) * this->ColorMapSize *
|
|
this->InverseFieldDelta);
|
|
colorIdx =
|
|
vtkm::Min(vtkm::Int32(this->ColorMap.GetNumberOfValues() - 1), vtkm::Max(0, colorIdx));
|
|
return this->ColorMap.Get(colorIdx);
|
|
}
|
|
|
|
VTKM_EXEC
|
|
void Plot(vtkm::Float32 x,
|
|
vtkm::Float32 y,
|
|
vtkm::Float32 depth,
|
|
const vtkm::Vec4f_32& color,
|
|
vtkm::Float32 intensity) const
|
|
{
|
|
vtkm::Id xi = static_cast<vtkm::Id>(x), yi = static_cast<vtkm::Id>(y);
|
|
if (xi < 0 || xi >= Width || yi < 0 || yi >= Height)
|
|
{
|
|
return;
|
|
}
|
|
vtkm::Id index = yi * Width + xi;
|
|
PackedValue current, next;
|
|
current.Raw = ClearValue;
|
|
next.Floats.Depth = depth;
|
|
vtkm::Vec4f_32 blendedColor;
|
|
vtkm::Vec4f_32 srcColor;
|
|
do
|
|
{
|
|
UnpackColor(current.Ints.Color, srcColor);
|
|
vtkm::Float32 inverseIntensity = (1.0f - intensity);
|
|
vtkm::Float32 alpha = srcColor[3] * inverseIntensity;
|
|
blendedColor[0] = color[0] * intensity + srcColor[0] * alpha;
|
|
blendedColor[1] = color[1] * intensity + srcColor[1] * alpha;
|
|
blendedColor[2] = color[2] * intensity + srcColor[2] * alpha;
|
|
blendedColor[3] = alpha + intensity;
|
|
next.Ints.Color = PackColor(blendedColor);
|
|
FrameBuffer.CompareExchange(index, ¤t.Raw, next.Raw);
|
|
} while (current.Floats.Depth > next.Floats.Depth);
|
|
}
|
|
|
|
vtkm::Matrix<vtkm::Float32, 4, 4> WorldToProjection;
|
|
vtkm::Id Width;
|
|
vtkm::Id Height;
|
|
vtkm::Id SubsetWidth;
|
|
vtkm::Id SubsetHeight;
|
|
vtkm::Id XOffset;
|
|
vtkm::Id YOffset;
|
|
bool AssocPoints;
|
|
ColorMapPortalConst ColorMap;
|
|
vtkm::Float32 ColorMapSize;
|
|
AtomicPackedFrameBufferHandle FrameBuffer;
|
|
vtkm::Float32 FieldMin;
|
|
vtkm::Float32 InverseFieldDelta;
|
|
vtkm::Float32 Offset;
|
|
};
|
|
|
|
struct BufferConverter : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
VTKM_CONT
|
|
BufferConverter() {}
|
|
|
|
using ControlSignature = void(FieldIn, WholeArrayOut, WholeArrayOut);
|
|
using ExecutionSignature = void(_1, _2, _3, WorkIndex);
|
|
|
|
template <typename DepthBufferPortalType, typename ColorBufferPortalType>
|
|
VTKM_EXEC void operator()(const vtkm::Int64& packedValue,
|
|
DepthBufferPortalType& depthBuffer,
|
|
ColorBufferPortalType& colorBuffer,
|
|
const vtkm::Id& index) const
|
|
{
|
|
PackedValue packed;
|
|
packed.Raw = packedValue;
|
|
float depth = packed.Floats.Depth;
|
|
if (depth <= depthBuffer.Get(index))
|
|
{
|
|
vtkm::Vec4f_32 color;
|
|
UnpackColor(packed.Ints.Color, color);
|
|
colorBuffer.Set(index, color);
|
|
depthBuffer.Set(index, depth);
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
class Wireframer
|
|
{
|
|
public:
|
|
VTKM_CONT
|
|
Wireframer(vtkm::rendering::Canvas* canvas, bool showInternalZones, bool isOverlay)
|
|
: Canvas(canvas)
|
|
, ShowInternalZones(showInternalZones)
|
|
, IsOverlay(isOverlay)
|
|
{
|
|
}
|
|
|
|
VTKM_CONT
|
|
void SetCamera(const vtkm::rendering::Camera& camera) { this->Camera = camera; }
|
|
|
|
VTKM_CONT
|
|
void SetColorMap(const ColorMapHandle& colorMap) { this->ColorMap = colorMap; }
|
|
|
|
VTKM_CONT
|
|
void SetSolidDepthBuffer(const vtkm::cont::ArrayHandle<vtkm::Float32> depthBuffer)
|
|
{
|
|
this->SolidDepthBuffer = depthBuffer;
|
|
}
|
|
|
|
VTKM_CONT
|
|
void SetData(const vtkm::cont::CoordinateSystem& coords,
|
|
const IndicesHandle& endPointIndices,
|
|
const vtkm::cont::Field& field,
|
|
const vtkm::Range& fieldRange)
|
|
{
|
|
this->Bounds = coords.GetBounds();
|
|
this->Coordinates = coords;
|
|
this->PointIndices = endPointIndices;
|
|
this->ScalarField = field;
|
|
this->ScalarFieldRange = fieldRange;
|
|
}
|
|
|
|
VTKM_CONT
|
|
void Render()
|
|
{
|
|
RenderWithDeviceFunctor functor(this);
|
|
vtkm::cont::TryExecute(functor);
|
|
}
|
|
|
|
private:
|
|
template <typename DeviceTag>
|
|
VTKM_CONT void RenderWithDevice(DeviceTag)
|
|
{
|
|
|
|
// The wireframe should appear on top of any prerendered data, and hide away the internal
|
|
// zones if `ShowInternalZones` is set to false. Since the prerendered data (or the solid
|
|
// depth buffer) could cause z-fighting with the wireframe, we will offset all the edges in Z
|
|
// by a small amount, proportional to distance between the near and far camera planes, in the
|
|
// camera space.
|
|
vtkm::Range clippingRange = Camera.GetClippingRange();
|
|
vtkm::Float64 offset1 = (clippingRange.Max - clippingRange.Min) / 1.0e4;
|
|
vtkm::Float64 offset2 = clippingRange.Min / 2.0;
|
|
vtkm::Float32 offset = static_cast<vtkm::Float32>(vtkm::Min(offset1, offset2));
|
|
vtkm::Matrix<vtkm::Float32, 4, 4> modelMatrix;
|
|
vtkm::MatrixIdentity(modelMatrix);
|
|
modelMatrix[2][3] = offset;
|
|
vtkm::Matrix<vtkm::Float32, 4, 4> worldToCamera =
|
|
vtkm::MatrixMultiply(modelMatrix, Camera.CreateViewMatrix());
|
|
vtkm::Matrix<vtkm::Float32, 4, 4> WorldToProjection = vtkm::MatrixMultiply(
|
|
Camera.CreateProjectionMatrix(Canvas->GetWidth(), Canvas->GetHeight()), worldToCamera);
|
|
|
|
vtkm::Id width = static_cast<vtkm::Id>(Canvas->GetWidth());
|
|
vtkm::Id height = static_cast<vtkm::Id>(Canvas->GetHeight());
|
|
vtkm::Id pixelCount = width * height;
|
|
|
|
if (this->ShowInternalZones && !this->IsOverlay)
|
|
{
|
|
vtkm::cont::ArrayHandleConstant<vtkm::Int64> clear(ClearValue, pixelCount);
|
|
vtkm::cont::Algorithm::Copy(clear, this->FrameBuffer);
|
|
}
|
|
else
|
|
{
|
|
VTKM_ASSERT(this->SolidDepthBuffer.GetNumberOfValues() == pixelCount);
|
|
CopyIntoFrameBuffer bufferCopy;
|
|
vtkm::worklet::DispatcherMapField<CopyIntoFrameBuffer>(bufferCopy)
|
|
.Invoke(this->Canvas->GetColorBuffer(), this->SolidDepthBuffer, this->FrameBuffer);
|
|
}
|
|
//
|
|
// detect a 2D camera and set the correct viewport.
|
|
// The View port specifies what the region of the screen
|
|
// to draw to which baiscally modifies the width and the
|
|
// height of the "canvas"
|
|
//
|
|
vtkm::Id xOffset = 0;
|
|
vtkm::Id yOffset = 0;
|
|
vtkm::Id subsetWidth = width;
|
|
vtkm::Id subsetHeight = height;
|
|
|
|
bool ortho2d = Camera.GetMode() == vtkm::rendering::Camera::Mode::TwoD;
|
|
if (ortho2d)
|
|
{
|
|
vtkm::Float32 vl, vr, vb, vt;
|
|
Camera.GetRealViewport(width, height, vl, vr, vb, vt);
|
|
vtkm::Float32 _x = static_cast<vtkm::Float32>(width) * (1.f + vl) / 2.f;
|
|
vtkm::Float32 _y = static_cast<vtkm::Float32>(height) * (1.f + vb) / 2.f;
|
|
vtkm::Float32 _w = static_cast<vtkm::Float32>(width) * (vr - vl) / 2.f;
|
|
vtkm::Float32 _h = static_cast<vtkm::Float32>(height) * (vt - vb) / 2.f;
|
|
|
|
subsetWidth = static_cast<vtkm::Id>(_w);
|
|
subsetHeight = static_cast<vtkm::Id>(_h);
|
|
yOffset = static_cast<vtkm::Id>(_y);
|
|
xOffset = static_cast<vtkm::Id>(_x);
|
|
}
|
|
|
|
const bool isSupportedField = ScalarField.IsCellField() || ScalarField.IsPointField();
|
|
if (!isSupportedField)
|
|
{
|
|
throw vtkm::cont::ErrorBadValue("Field not associated with cell set or points");
|
|
}
|
|
const bool isAssocPoints = ScalarField.IsPointField();
|
|
|
|
{
|
|
vtkm::cont::Token token;
|
|
EdgePlotter<DeviceTag> plotter(WorldToProjection,
|
|
width,
|
|
height,
|
|
subsetWidth,
|
|
subsetHeight,
|
|
xOffset,
|
|
yOffset,
|
|
isAssocPoints,
|
|
ScalarFieldRange,
|
|
ColorMap,
|
|
FrameBuffer,
|
|
Camera.GetClippingRange(),
|
|
token);
|
|
vtkm::worklet::DispatcherMapField<EdgePlotter<DeviceTag>> plotterDispatcher(plotter);
|
|
plotterDispatcher.SetDevice(DeviceTag());
|
|
plotterDispatcher.Invoke(
|
|
PointIndices, Coordinates, vtkm::rendering::raytracing::GetScalarFieldArray(ScalarField));
|
|
}
|
|
|
|
BufferConverter converter;
|
|
vtkm::worklet::DispatcherMapField<BufferConverter> converterDispatcher(converter);
|
|
converterDispatcher.SetDevice(DeviceTag());
|
|
converterDispatcher.Invoke(FrameBuffer, Canvas->GetDepthBuffer(), Canvas->GetColorBuffer());
|
|
}
|
|
|
|
VTKM_CONT
|
|
struct RenderWithDeviceFunctor
|
|
{
|
|
Wireframer* Renderer;
|
|
|
|
RenderWithDeviceFunctor(Wireframer* renderer)
|
|
: Renderer(renderer)
|
|
{
|
|
}
|
|
|
|
template <typename DeviceTag>
|
|
VTKM_CONT bool operator()(DeviceTag)
|
|
{
|
|
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceTag);
|
|
Renderer->RenderWithDevice(DeviceTag());
|
|
return true;
|
|
}
|
|
};
|
|
|
|
vtkm::Bounds Bounds;
|
|
vtkm::rendering::Camera Camera;
|
|
vtkm::rendering::Canvas* Canvas;
|
|
bool ShowInternalZones;
|
|
bool IsOverlay;
|
|
ColorMapHandle ColorMap;
|
|
vtkm::cont::CoordinateSystem Coordinates;
|
|
IndicesHandle PointIndices;
|
|
vtkm::cont::Field ScalarField;
|
|
vtkm::Range ScalarFieldRange;
|
|
vtkm::cont::ArrayHandle<vtkm::Float32> SolidDepthBuffer;
|
|
PackedFrameBufferHandle FrameBuffer;
|
|
}; // class Wireframer
|
|
}
|
|
} //namespace vtkm::rendering
|
|
|
|
#endif //vtk_m_rendering_Wireframer_h
|