//============================================================================ // 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 #include #include #include #include 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& color, vtkm::Id width, vtkm::Id height) : Color(color) , Width(width) , Height(height) { } template VTKM_EXEC void operator()(const vtkm::Vec& screenCoords, const vtkm::Vec& textureCoords, const FontTexture& fontTexture, ColorBufferPortal& colorBuffer) const { vtkm::Float32 x0 = Clamp(screenCoords[0], 0.0f, static_cast(Width - 1)); vtkm::Float32 x1 = Clamp(screenCoords[2], 0.0f, static_cast(Width - 1)); vtkm::Float32 y0 = Clamp(screenCoords[1], 0.0f, static_cast(Height - 1)); vtkm::Float32 y1 = Clamp(screenCoords[3], 0.0f, static_cast(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 void Plot(vtkm::Float32 x, vtkm::Float32 y, vtkm::Float32 intensity, ColorBufferPortal& colorBuffer) const { vtkm::Id index = static_cast(vtkm::Round(y)) * Width + static_cast(vtkm::Round(x)); vtkm::Vec srcColor = colorBuffer.Get(index); intensity = intensity * Color[3]; vtkm::Float32 inverseIntensity = 1.0f - intensity; vtkm::Float32 alpha = srcColor[3] * inverseIntensity; vtkm::Vec 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 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 = vtkm::cont::ArrayHandle>; using TextureCoordsArrayHandle = vtkm::cont::ArrayHandle>; VTKM_CONT RenderBitmapFontExecutor(const ScreenCoordsArrayHandle& screenCoords, const TextureCoordsArrayHandle& textureCoords, const FontTextureType& fontTexture, const vtkm::Vec& color, const ColorBufferType& colorBuffer, vtkm::Id width, vtkm::Id height) : ScreenCoords(screenCoords) , TextureCoords(textureCoords) , FontTexture(fontTexture) , ColorBuffer(colorBuffer) , Worklet(color, width, height) { } template VTKM_CONT bool operator()(Device) const { VTKM_IS_DEVICE_ADAPTER_TAG(Device); vtkm::worklet::DispatcherMapField dispatcher(Worklet); dispatcher.Invoke( ScreenCoords, TextureCoords, FontTexture.GetExecObject(), ColorBuffer); return true; } ScreenCoordsArrayHandle ScreenCoords; TextureCoordsArrayHandle TextureCoords; FontTextureType FontTexture; ColorBufferType ColorBuffer; RenderBitmapFont Worklet; }; // struct RenderBitmapFontExecutor } // namespace internal TextRenderer::TextRenderer(const 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& position, vtkm::Float32 scale, vtkm::Float32 angle, vtkm::Float32 windowAspect, const vtkm::Vec& anchor, const vtkm::rendering::Color& color, const std::string& text) { vtkm::Matrix translationMatrix = Transform3DTranslate(position[0], position[1], 0.f); vtkm::Matrix scaleMatrix = Transform3DScale(1.0f / windowAspect, 1.0f, 1.0f); vtkm::Vec rotationAxis(0.0f, 0.0f, 1.0f); vtkm::Matrix rotationMatrix = Transform3DRotate(angle, rotationAxis); vtkm::Matrix transform = vtkm::MatrixMultiply(translationMatrix, vtkm::MatrixMultiply(scaleMatrix, rotationMatrix)); RenderText(transform, scale, anchor, color, text); } void TextRenderer::RenderText(const vtkm::Vec& origin, const vtkm::Vec& right, const vtkm::Vec& up, vtkm::Float32 scale, const vtkm::Vec& anchor, const vtkm::rendering::Color& color, const std::string& text) { vtkm::Vec n = vtkm::Cross(right, up); vtkm::Normalize(n); vtkm::Matrix transform = MatrixHelpers::WorldMatrix(origin, right, up, n); transform = vtkm::MatrixMultiply(Canvas->GetModelView(), transform); transform = vtkm::MatrixMultiply(Canvas->GetProjection(), transform); RenderText(transform, scale, anchor, color, text); } void TextRenderer::RenderText(const vtkm::Matrix& transform, vtkm::Float32 scale, const vtkm::Vec& 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 = internal::RenderBitmapFontExecutor::ScreenCoordsArrayHandle; using TextureCoordsArrayHandle = internal::RenderBitmapFontExecutor::TextureCoordsArrayHandle; ScreenCoordsArrayHandle screenCoords; TextureCoordsArrayHandle textureCoords; screenCoords.Allocate(static_cast(text.length())); textureCoords.Allocate(static_cast(text.length())); ScreenCoordsArrayHandle::PortalControl screenCoordsPortal = screenCoords.GetPortalControl(); TextureCoordsArrayHandle::PortalControl textureCoordsPortal = textureCoords.GetPortalControl(); vtkm::Vec 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(p0[0], p1[1], p1[0], p0[1]); screenCoordsPortal.Set(static_cast(i), charCoords); textureCoordsPortal.Set(static_cast(i), charUVs); } vtkm::cont::TryExecute(internal::RenderBitmapFontExecutor(screenCoords, textureCoords, FontTexture, color.Components, Canvas->GetColorBuffer(), Canvas->GetWidth(), Canvas->GetHeight())); } } } // namespace vtkm::rendering