254 lines
10 KiB
C++
254 lines
10 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.
|
||
|
//
|
||
|
// Copyright 2016 Sandia Corporation.
|
||
|
// Copyright 2016 UT-Battelle, LLC.
|
||
|
// Copyright 2016 Los Alamos National Security.
|
||
|
//
|
||
|
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
||
|
// the U.S. Government retains certain rights in this software.
|
||
|
//
|
||
|
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
|
||
|
// Laboratory (LANL), the U.S. Government retains certain rights in
|
||
|
// this software.
|
||
|
//============================================================================
|
||
|
|
||
|
#include <vtkm/rendering/TextRenderer.h>
|
||
|
|
||
|
#include <vtkm/Transform3D.h>
|
||
|
#include <vtkm/cont/TryExecute.h>
|
||
|
#include <vtkm/worklet/DispatcherMapField.h>
|
||
|
#include <vtkm/worklet/WorkletMapField.h>
|
||
|
|
||
|
namespace vtkm
|
||
|
{
|
||
|
namespace rendering
|
||
|
{
|
||
|
namespace internal
|
||
|
{
|
||
|
|
||
|
struct RenderBitmapFont : public vtkm::worklet::WorkletMapField
|
||
|
{
|
||
|
using ColorBufferType = vtkm::rendering::Canvas::ColorBufferType;
|
||
|
using FontTextureType = vtkm::rendering::Canvas::FontTextureType;
|
||
|
|
||
|
typedef void ControlSignature(FieldIn<>, FieldIn<>, ExecObject, WholeArrayInOut<>);
|
||
|
typedef void ExecutionSignature(_1, _2, _3, _4);
|
||
|
using InputDomain = _1;
|
||
|
|
||
|
VTKM_CONT
|
||
|
RenderBitmapFont() {}
|
||
|
|
||
|
VTKM_CONT
|
||
|
RenderBitmapFont(const vtkm::Vec<vtkm::Float32, 4>& color, vtkm::Id width, vtkm::Id height)
|
||
|
: Color(color)
|
||
|
, Width(width)
|
||
|
, Height(height)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
template <typename ColorBufferPortal, typename FontTexture>
|
||
|
VTKM_EXEC void operator()(const vtkm::Vec<vtkm::Float32, 4>& screenCoords,
|
||
|
const vtkm::Vec<vtkm::Float32, 4>& textureCoords,
|
||
|
const FontTexture& fontTexture,
|
||
|
ColorBufferPortal& colorBuffer) const
|
||
|
{
|
||
|
vtkm::Float32 x0 = Clamp(screenCoords[0], 0.0f, static_cast<vtkm::Float32>(Width - 1));
|
||
|
vtkm::Float32 x1 = Clamp(screenCoords[2], 0.0f, static_cast<vtkm::Float32>(Width - 1));
|
||
|
vtkm::Float32 y0 = Clamp(screenCoords[1], 0.0f, static_cast<vtkm::Float32>(Height - 1));
|
||
|
vtkm::Float32 y1 = Clamp(screenCoords[3], 0.0f, static_cast<vtkm::Float32>(Height - 1));
|
||
|
|
||
|
// For crisp text rendering, we sample the font texture at points smaller than the pixel
|
||
|
// sizes. Here we sample at increments of 0.25f, and scale the reported intensities accordingly
|
||
|
vtkm::Float32 dx = x1 - x0, dy = y1 - y0;
|
||
|
for (vtkm::Float32 x = x0; x <= x1; x += 0.25f)
|
||
|
{
|
||
|
for (vtkm::Float32 y = y0; y <= y1; y += 0.25f)
|
||
|
{
|
||
|
vtkm::Float32 tu = x1 == x0 ? 1.0f : (x - x0) / dx;
|
||
|
vtkm::Float32 tv = y1 == y0 ? 1.0f : (y - y0) / dy;
|
||
|
vtkm::Float32 u = vtkm::Lerp(textureCoords[0], textureCoords[2], tu);
|
||
|
vtkm::Float32 v = vtkm::Lerp(textureCoords[1], textureCoords[3], tv);
|
||
|
vtkm::Float32 intensity = fontTexture.GetColor(u, v)[0] * 0.25f;
|
||
|
Plot(x, y, intensity, colorBuffer);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename ColorBufferPortal>
|
||
|
void Plot(vtkm::Float32 x,
|
||
|
vtkm::Float32 y,
|
||
|
vtkm::Float32 intensity,
|
||
|
ColorBufferPortal& colorBuffer) const
|
||
|
{
|
||
|
vtkm::Id index =
|
||
|
static_cast<vtkm::Id>(vtkm::Round(y)) * Width + static_cast<vtkm::Id>(vtkm::Round(x));
|
||
|
vtkm::Vec<vtkm::Float32, 4> srcColor = colorBuffer.Get(index);
|
||
|
intensity = intensity * Color[3];
|
||
|
vtkm::Float32 inverseIntensity = 1.0f - intensity;
|
||
|
vtkm::Float32 alpha = srcColor[3] * inverseIntensity;
|
||
|
vtkm::Vec<vtkm::Float32, 4> blendedColor;
|
||
|
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;
|
||
|
colorBuffer.Set(index, blendedColor);
|
||
|
}
|
||
|
|
||
|
VTKM_EXEC
|
||
|
vtkm::Float32 Clamp(vtkm::Float32 v, vtkm::Float32 min, vtkm::Float32 max) const
|
||
|
{
|
||
|
return vtkm::Min(vtkm::Max(v, min), max);
|
||
|
}
|
||
|
|
||
|
vtkm::Vec<vtkm::Float32, 4> Color;
|
||
|
vtkm::Id Width;
|
||
|
vtkm::Id Height;
|
||
|
}; // struct RenderBitmapFont
|
||
|
|
||
|
struct RenderBitmapFontExecutor
|
||
|
{
|
||
|
using ColorBufferType = vtkm::rendering::Canvas::ColorBufferType;
|
||
|
using FontTextureType = vtkm::rendering::Canvas::FontTextureType;
|
||
|
using ScreenCoordsArrayHandle = typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>;
|
||
|
using TextureCoordsArrayHandle = typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>;
|
||
|
|
||
|
VTKM_CONT
|
||
|
RenderBitmapFontExecutor(const ScreenCoordsArrayHandle& screenCoords,
|
||
|
const TextureCoordsArrayHandle& textureCoords,
|
||
|
const FontTextureType& fontTexture,
|
||
|
const vtkm::Vec<vtkm::Float32, 4>& color,
|
||
|
const ColorBufferType& colorBuffer,
|
||
|
vtkm::Id width,
|
||
|
vtkm::Id height)
|
||
|
: ScreenCoords(screenCoords)
|
||
|
, TextureCoords(textureCoords)
|
||
|
, FontTexture(fontTexture)
|
||
|
, ColorBuffer(colorBuffer)
|
||
|
, Worklet(color, width, height)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
template <typename Device>
|
||
|
VTKM_CONT bool operator()(Device) const
|
||
|
{
|
||
|
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
|
||
|
|
||
|
vtkm::worklet::DispatcherMapField<RenderBitmapFont, Device> dispatcher(Worklet);
|
||
|
dispatcher.Invoke(
|
||
|
ScreenCoords, TextureCoords, FontTexture.GetExecObject<Device>(), ColorBuffer);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
ScreenCoordsArrayHandle ScreenCoords;
|
||
|
TextureCoordsArrayHandle TextureCoords;
|
||
|
FontTextureType FontTexture;
|
||
|
ColorBufferType ColorBuffer;
|
||
|
RenderBitmapFont Worklet;
|
||
|
}; // struct RenderBitmapFontExecutor
|
||
|
} // namespace internal
|
||
|
|
||
|
TextRenderer::TextRenderer(vtkm::rendering::Canvas* canvas,
|
||
|
const vtkm::rendering::BitmapFont& font,
|
||
|
const vtkm::rendering::Canvas::FontTextureType& fontTexture)
|
||
|
: Canvas(canvas)
|
||
|
, Font(font)
|
||
|
, FontTexture(fontTexture)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void TextRenderer::RenderText(const vtkm::Vec<vtkm::Float32, 2>& position,
|
||
|
vtkm::Float32 scale,
|
||
|
vtkm::Float32 angle,
|
||
|
vtkm::Float32 windowAspect,
|
||
|
const vtkm::Vec<vtkm::Float32, 2>& anchor,
|
||
|
const vtkm::rendering::Color& color,
|
||
|
const std::string& text)
|
||
|
{
|
||
|
vtkm::Matrix<vtkm::Float32, 4, 4> translationMatrix =
|
||
|
Transform3DTranslate(position[0], position[1], 0.f);
|
||
|
vtkm::Matrix<vtkm::Float32, 4, 4> scaleMatrix = Transform3DScale(1.0f / windowAspect, 1.0f, 1.0f);
|
||
|
vtkm::Vec<vtkm::Float32, 3> rotationAxis(0.0f, 0.0f, 1.0f);
|
||
|
vtkm::Matrix<vtkm::Float32, 4, 4> rotationMatrix = Transform3DRotate(angle, rotationAxis);
|
||
|
vtkm::Matrix<vtkm::Float32, 4, 4> transform =
|
||
|
vtkm::MatrixMultiply(translationMatrix, vtkm::MatrixMultiply(scaleMatrix, rotationMatrix));
|
||
|
RenderText(transform, scale, anchor, color, text);
|
||
|
}
|
||
|
|
||
|
void TextRenderer::RenderText(const vtkm::Vec<vtkm::Float32, 3>& origin,
|
||
|
const vtkm::Vec<vtkm::Float32, 3>& right,
|
||
|
const vtkm::Vec<vtkm::Float32, 3>& up,
|
||
|
vtkm::Float32 scale,
|
||
|
const vtkm::Vec<vtkm::Float32, 2>& anchor,
|
||
|
const vtkm::rendering::Color& color,
|
||
|
const std::string& text)
|
||
|
{
|
||
|
vtkm::Vec<vtkm::Float32, 3> n = vtkm::Cross(right, up);
|
||
|
vtkm::Normalize(n);
|
||
|
|
||
|
vtkm::Matrix<vtkm::Float32, 4, 4> transform = MatrixHelpers::WorldMatrix(origin, right, up, n);
|
||
|
RenderText(transform, scale, anchor, color, text);
|
||
|
}
|
||
|
|
||
|
void TextRenderer::RenderText(const vtkm::Matrix<vtkm::Float32, 4, 4>& transform,
|
||
|
vtkm::Float32 scale,
|
||
|
const vtkm::Vec<vtkm::Float32, 2>& anchor,
|
||
|
const vtkm::rendering::Color& color,
|
||
|
const std::string& text)
|
||
|
{
|
||
|
vtkm::Float32 textWidth = this->Font.GetTextWidth(text);
|
||
|
vtkm::Float32 fx = -(0.5f + 0.5f * anchor[0]) * textWidth;
|
||
|
vtkm::Float32 fy = -(0.5f + 0.5f * anchor[1]);
|
||
|
vtkm::Float32 fz = 0;
|
||
|
|
||
|
using ScreenCoordsArrayHandle =
|
||
|
typename internal::RenderBitmapFontExecutor::ScreenCoordsArrayHandle;
|
||
|
using TextureCoordsArrayHandle =
|
||
|
typename internal::RenderBitmapFontExecutor::TextureCoordsArrayHandle;
|
||
|
ScreenCoordsArrayHandle screenCoords;
|
||
|
TextureCoordsArrayHandle textureCoords;
|
||
|
screenCoords.Allocate(static_cast<vtkm::Id>(text.length()));
|
||
|
textureCoords.Allocate(static_cast<vtkm::Id>(text.length()));
|
||
|
ScreenCoordsArrayHandle::PortalControl screenCoordsPortal = screenCoords.GetPortalControl();
|
||
|
TextureCoordsArrayHandle::PortalControl textureCoordsPortal = textureCoords.GetPortalControl();
|
||
|
vtkm::Vec<vtkm::Float32, 4> charVertices, charUVs, charCoords;
|
||
|
for (std::size_t i = 0; i < text.length(); ++i)
|
||
|
{
|
||
|
char c = text[i];
|
||
|
char nextchar = (i < text.length() - 1) ? text[i + 1] : 0;
|
||
|
Font.GetCharPolygon(c,
|
||
|
fx,
|
||
|
fy,
|
||
|
charVertices[0],
|
||
|
charVertices[2],
|
||
|
charVertices[3],
|
||
|
charVertices[1],
|
||
|
charUVs[0],
|
||
|
charUVs[2],
|
||
|
charUVs[3],
|
||
|
charUVs[1],
|
||
|
nextchar);
|
||
|
charVertices = charVertices * scale;
|
||
|
vtkm::Id2 p0 = Canvas->GetScreenPoint(charVertices[0], charVertices[3], fz, transform);
|
||
|
vtkm::Id2 p1 = Canvas->GetScreenPoint(charVertices[2], charVertices[1], fz, transform);
|
||
|
charCoords = vtkm::Vec<vtkm::Id, 4>(p0[0], p1[1], p1[0], p0[1]);
|
||
|
screenCoordsPortal.Set(i, charCoords);
|
||
|
textureCoordsPortal.Set(i, charUVs);
|
||
|
}
|
||
|
|
||
|
vtkm::cont::TryExecute(internal::RenderBitmapFontExecutor(screenCoords,
|
||
|
textureCoords,
|
||
|
FontTexture,
|
||
|
color.Components,
|
||
|
Canvas->GetColorBuffer(),
|
||
|
Canvas->GetWidth(),
|
||
|
Canvas->GetHeight()));
|
||
|
}
|
||
|
}
|
||
|
} // namespace vtkm::rendering
|