Commit 0455845f authored by David C. Lonie's avatar David C. Lonie

Add vtkBillboardTextActor3D.

vtkBillboardTextActor3D is anchored and aligned to a 3D point, but
is always oriented towards the camera and scaled for pixel/texel
alignment.

Also updated and tested the GL2PS export for this class.
parent 82a30ba3
......@@ -3,6 +3,7 @@ include(vtkGhostscript)
# Only run GL2PS tests if GhostScript is available
if(VTK_GHOSTSCRIPT_EXECUTABLE)
set(GL2PSTests
TestGL2PSBillboardTextActor3D.cxx
TestGL2PSExporterMultipleRenderers.cxx
TestGL2PSExporterRaster.cxx
TestGL2PSExporterVolumeRaster.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestGL2PSBillboardTextActor3D.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm 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.
=========================================================================*/
// Note: The output of this test will be different on OpenGL2 -- all text will
// be rendered atop the polygonal geometry. This is because we do not yet
// export 3D geometry as vector primitives in OpenGL2, but rather rasterize it
// into the background.
//
// OpenGL1 should mix the text with the geometry.
#include "vtkBillboardTextActor3D.h"
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkGL2PSExporter.h"
#include "vtkNew.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkTestingInteractor.h"
#include "vtkTextProperty.h"
#include "vtkUnsignedCharArray.h"
#include <sstream>
#include <vector>
namespace vtkTestGL2PSBillboardTextActor3D {
void setupBillboardTextActor3D(vtkBillboardTextActor3D *actor,
vtkPolyData *anchor)
{
vtkTextProperty *p = actor->GetTextProperty();
std::ostringstream label;
label << "TProp Angle: " << p->GetOrientation() << "\n"
<< "HAlign: " << p->GetJustificationAsString() << "\n"
<< "VAlign: " << p->GetVerticalJustificationAsString();
actor->SetInput(label.str().c_str());
// Add the anchor point:
double *pos = actor->GetPosition();
double *col = p->GetColor();
vtkIdType ptId = anchor->GetPoints()->InsertNextPoint(pos[0], pos[1], pos[2]);
anchor->GetVerts()->InsertNextCell(1, &ptId);
anchor->GetCellData()->GetScalars()->InsertNextTuple4(col[0] * 255,
col[1] * 255,
col[2] * 255, 255);
}
void setupGrid(vtkPolyData *grid)
{
double marks[4] = {0., 200., 400., 600.};
double thickness = 200.;
vtkNew<vtkPoints> points;
grid->SetPoints(points.Get());
for (int x_i = 0; x_i < 4; ++x_i)
{
for (int y_i = 0; y_i < 4; ++y_i)
{
points->InsertNextPoint(marks[x_i], marks[y_i], -thickness / 2.);
points->InsertNextPoint(marks[x_i], marks[y_i], +thickness / 2.);
}
}
std::vector<vtkIdType> quads;
for (vtkIdType col = 0; col < 4; ++col)
{
for (int row = 0; row < 3; ++row)
{
// Along y:
vtkIdType base = 8 * col + 2 * row;
quads.push_back(base + 0);
quads.push_back(base + 1);
quads.push_back(base + 3);
quads.push_back(base + 2);
}
}
vtkNew<vtkCellArray> cellArray;
grid->SetPolys(cellArray.Get());
for (size_t i = 0; i < quads.size(); i += 4)
{
grid->InsertNextCell(VTK_QUAD, 4, &quads[i]);
}
}
} // end namespace vtkTestGL2PSBillboardTextActor3D
//----------------------------------------------------------------------------
int TestGL2PSBillboardTextActor3D(int, char *[])
{
using namespace vtkTestGL2PSBillboardTextActor3D;
vtkNew<vtkRenderer> ren;
ren->UseDepthPeelingOn();
int width = 600;
int height = 600;
int x[3] = {100, 300, 500};
int y[3] = {100, 300, 500};
// Render the anchor points to check alignment:
vtkNew<vtkPolyData> anchors;
vtkNew<vtkPoints> points;
anchors->SetPoints(points.GetPointer());
vtkNew<vtkCellArray> verts;
anchors->SetVerts(verts.GetPointer());
vtkNew<vtkUnsignedCharArray> colors;
colors->SetNumberOfComponents(4);
anchors->GetCellData()->SetScalars(colors.GetPointer());
for (size_t row = 0; row < 3; ++row)
{
for (size_t col = 0; col < 3; ++col)
{
vtkNew<vtkBillboardTextActor3D> actor;
switch (row)
{
case 0:
actor->GetTextProperty()->SetJustificationToRight();
break;
case 1:
actor->GetTextProperty()->SetJustificationToCentered();
break;
case 2:
actor->GetTextProperty()->SetJustificationToLeft();
break;
}
switch (col)
{
case 0:
actor->GetTextProperty()->SetVerticalJustificationToBottom();
break;
case 1:
actor->GetTextProperty()->SetVerticalJustificationToCentered();
break;
case 2:
actor->GetTextProperty()->SetVerticalJustificationToTop();
break;
}
actor->GetTextProperty()->SetFontSize(20);
actor->GetTextProperty()->SetOrientation(45.0 * (3 * row + col));
actor->GetTextProperty()->SetColor(0.75, .2 + col * .26, .2 + row * .26);
actor->GetTextProperty()->SetBackgroundColor(0.,
1. - col * .26,
1. - row * .26);
actor->GetTextProperty()->SetBackgroundOpacity(0.85);
actor->SetPosition(x[col], y[row], 0.);
setupBillboardTextActor3D(actor.GetPointer(), anchors.GetPointer());
ren->AddActor(actor.GetPointer());
}
}
vtkNew<vtkPolyDataMapper> anchorMapper;
anchorMapper->SetInputData(anchors.GetPointer());
vtkNew<vtkActor> anchorActor;
anchorActor->SetMapper(anchorMapper.GetPointer());
anchorActor->GetProperty()->SetPointSize(5);
ren->AddActor(anchorActor.GetPointer());
// Add some various 'empty' actors to make sure there are no surprises:
vtkNew<vtkBillboardTextActor3D> nullInputActor;
nullInputActor->SetInput(NULL);
ren->AddActor(nullInputActor.GetPointer());
vtkNew<vtkBillboardTextActor3D> emptyInputActor;
emptyInputActor->SetInput("");
ren->AddActor(emptyInputActor.GetPointer());
vtkNew<vtkBillboardTextActor3D> spaceActor;
spaceActor->SetInput(" ");
ren->AddActor(spaceActor.GetPointer());
vtkNew<vtkBillboardTextActor3D> tabActor;
tabActor->SetInput("\t");
ren->AddActor(tabActor.GetPointer());
vtkNew<vtkBillboardTextActor3D> newlineActor;
newlineActor->SetInput("\n");
ren->AddActor(newlineActor.GetPointer());
vtkNew<vtkPolyData> grid;
setupGrid(grid.Get());
vtkNew<vtkPolyDataMapper> gridMapper;
gridMapper->SetInputData(grid.Get());
vtkNew<vtkActor> gridActor;
gridActor->GetProperty()->SetRepresentationToSurface();
gridActor->GetProperty()->SetColor(0.6, 0.6, 0.6);
gridActor->SetMapper(gridMapper.Get());
ren->AddActor(gridActor.Get());
vtkNew<vtkRenderWindow> win;
win->AddRenderer(ren.GetPointer());
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(win.GetPointer());
ren->SetBackground(0.0, 0.0, 0.0);
ren->GetActiveCamera()->SetPosition(width/2, height/2, 1400);
ren->GetActiveCamera()->SetFocalPoint(width/2, height/2, 0);
ren->GetActiveCamera()->SetViewUp(0, 1, 0);
ren->GetActiveCamera()->Roll(45.);
ren->GetActiveCamera()->Elevation(45.);
ren->ResetCameraClippingRange();
win->SetSize(width, height);
win->Render();
vtkNew<vtkGL2PSExporter> exp;
exp->SetRenderWindow(win.GetPointer());
exp->SetFileFormatToPS();
exp->CompressOff();
exp->SetSortToSimple();
exp->DrawBackgroundOn();
exp->Write3DPropsAsRasterImageOff();
exp->TextAsPathOn();
std::string fileprefix = vtkTestingInteractor::TempDirectory +
std::string("/TestGL2PSBillboardTextActor3D");
exp->SetFilePrefix(fileprefix.c_str());
exp->Write();
// Finally render the scene and compare the image to a reference image
win->SetMultiSamples(0);
win->GetInteractor()->Initialize();
win->GetInteractor()->Start();
return EXIT_SUCCESS;
}
......@@ -19,6 +19,7 @@
#include "vtkActor2D.h"
#include "vtkActorCollection.h"
#include "vtkActor2DCollection.h"
#include "vtkBillboardTextActor3D.h"
#include "vtkCamera.h"
#include "vtkContext2D.h"
#include "vtkContextActor.h"
......@@ -585,12 +586,33 @@ void vtkOpenGLGL2PSExporter::HandleSpecialProp(vtkProp *prop, vtkRenderer *ren)
{
this->DrawTextActor3D(textAct3D, ren);
}
else if (vtkBillboardTextActor3D *billboardTextAct3D =
vtkBillboardTextActor3D::SafeDownCast(prop))
{
this->DrawBillboardTextActor3D(billboardTextAct3D, ren);
}
else // Some other prop
{
return;
}
}
void vtkOpenGLGL2PSExporter::
DrawBillboardTextActor3D(vtkBillboardTextActor3D *textAct, vtkRenderer *)
{
vtkOpenGLClearErrorMacro();
double textPosWC[3];
textAct->GetPosition(textPosWC);
double textPosDC[3];
textAct->GetAnchorDC(textPosDC);
vtkGL2PSUtilities::DrawString(textAct->GetInput(), textAct->GetTextProperty(),
textPosWC, textPosDC[2] + 1e-6);
vtkOpenGLCheckErrorMacro("failed after DrawBillboardTextActor3D");
}
void vtkOpenGLGL2PSExporter::DrawTextActor(vtkTextActor *textAct, vtkRenderer *ren)
{
const char *string = textAct->GetInput();
......
......@@ -84,6 +84,7 @@
class vtkActor;
class vtkActor2D;
class vtkBillboardTextActor3D;
class vtkCollection;
class vtkCoordinate;
class vtkImageData;
......@@ -135,6 +136,8 @@ protected:
* at the end of the override for default handling.
*/
virtual void HandleSpecialProp(vtkProp *prop, vtkRenderer *ren);
void DrawBillboardTextActor3D(vtkBillboardTextActor3D *textAct,
vtkRenderer *ren);
void DrawTextActor(vtkTextActor *textAct, vtkRenderer *ren);
void DrawTextActor3D(vtkTextActor3D *textAct, vtkRenderer *ren);
void DrawTextMapper(vtkTextMapper *textMap, vtkActor2D *textAct,
......
......@@ -9,6 +9,7 @@ set(Module_SRCS
vtkActor.cxx
vtkAssembly.cxx
vtkBackgroundColorMonitor.cxx
vtkBillboardTextActor3D.cxx
vtkCameraActor.cxx
vtkCamera.cxx
vtkCameraInterpolator.cxx
......
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkBillboardTextActor3D.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm 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.
=========================================================================*/
/**
* @class vtkBillboardTextActor3D
* @brief Renders pixel-aligned text, facing the camera, anchored at a 3D point.
*/
#ifndef vtkBillboardTextActor3D_h
#define vtkBillboardTextActor3D_h
#include "vtkRenderingCoreModule.h" // For export macro
#include "vtkProp3D.h"
#include "vtkNew.h" // For.... vtkNew!
class vtkActor;
class vtkImageData;
class vtkPolyData;
class vtkPolyDataMapper;
class vtkRenderer;
class vtkTextProperty;
class vtkTextRenderer;
class vtkTexture;
class VTKRENDERINGCORE_EXPORT vtkBillboardTextActor3D: public vtkProp3D
{
public:
static vtkBillboardTextActor3D* New();
vtkTypeMacro(vtkBillboardTextActor3D, vtkProp3D)
void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE;
/**
* The UTF-8 encoded string to display.
* @{
*/
void SetInput(const char *in);
vtkGetStringMacro(Input)
/** @} */
/**
* The vtkTextProperty object that controls the rendered text.
* @{
*/
void SetTextProperty(vtkTextProperty *tprop);
vtkGetObjectMacro(TextProperty, vtkTextProperty)
/** @} */
/**
* Always returns true, as we're rendering an RGBA texture.
*/
int HasTranslucentPolygonalGeometry() VTK_OVERRIDE { return 1; }
/**
* Check/update geometry/texture in opaque pass, since it only happens once.
*/
int RenderOpaqueGeometry(vtkViewport *vp) VTK_OVERRIDE;
/**
* Just render in translucent pass, since it can execute multiple times
* (depth peeling, for instance).
*/
int RenderTranslucentPolygonalGeometry(vtkViewport *vp) VTK_OVERRIDE;
void ReleaseGraphicsResources(vtkWindow *win) VTK_OVERRIDE;
double *GetBounds() VTK_OVERRIDE;
using Superclass::GetBounds;
/**
* Returns the anchor position in display coordinates, with depth in NDC.
* Valid after calling RenderOpaqueGeometry.
*/
vtkGetVector3Macro(AnchorDC, double)
protected:
vtkBillboardTextActor3D();
~vtkBillboardTextActor3D();
bool InputIsValid();
bool TextureIsStale(vtkRenderer *ren);
void GenerateTexture(vtkRenderer *ren);
bool QuadIsStale(vtkRenderer *ren);
void GenerateQuad(vtkRenderer *ren);
// Used by the opaque pass to tell the translucent pass not to render.
void Invalidate();
bool IsValid();
// Used to sync the internal actor's state.
void PreRender();
// Text specification:
char *Input;
vtkTextProperty *TextProperty;
// Cached metadata to determine if things need rebuildin'
int RenderedDPI;
vtkTimeStamp InputMTime;
// Rendering stuffies
vtkNew<vtkTextRenderer> TextRenderer;
vtkNew<vtkImageData> Image;
vtkNew<vtkTexture> Texture;
vtkNew<vtkPolyData> Quad;
vtkNew<vtkPolyDataMapper> QuadMapper;
vtkNew<vtkActor> QuadActor;
// Display coordinate for anchor position. Z value is in NDC.
// Cached for GL2PS export on OpenGL2:
double AnchorDC[3];
private:
vtkBillboardTextActor3D(const vtkBillboardTextActor3D&) VTK_DELETE_FUNCTION;
void operator=(const vtkBillboardTextActor3D&) VTK_DELETE_FUNCTION;
};
#endif // vtkBillboardTextActor3D_h
......@@ -4,6 +4,7 @@ set(TestMathTextFreeTypeTextRendererNoMath_ARGS
DATA{../Data/Fonts/DejaVuSans.ttf}
)
vtk_add_test_cxx(${vtk-module}CxxTests tests
TestBillboardTextActor3D.cxx
TestFTStringToPath.cxx
TestFreeTypeTextMapperNoMath.cxx
TestFreeTypeTools.cxx,NO_VALID
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestBillboardTextActor3D.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm 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.
=========================================================================*/
#include "vtkBillboardTextActor3D.h"
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkNew.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkTestingInteractor.h"
#include "vtkTextProperty.h"
#include "vtkUnsignedCharArray.h"
#include <sstream>
#include <vector>
namespace vtkTestBillboardTextActor3D {
void setupBillboardTextActor3D(vtkBillboardTextActor3D *actor,
vtkPolyData *anchor)
{
vtkTextProperty *p = actor->GetTextProperty();
std::ostringstream label;
label << "TProp Angle: " << p->GetOrientation() << "\n"
<< "HAlign: " << p->GetJustificationAsString() << "\n"
<< "VAlign: " << p->GetVerticalJustificationAsString();
actor->SetInput(label.str().c_str());
// Add the anchor point:
double *pos = actor->GetPosition();
double *col = p->GetColor();
vtkIdType ptId = anchor->GetPoints()->InsertNextPoint(pos[0], pos[1], pos[2]);
anchor->GetVerts()->InsertNextCell(1, &ptId);
anchor->GetCellData()->GetScalars()->InsertNextTuple4(col[0] * 255,
col[1] * 255,
col[2] * 255, 255);
}
void setupGrid(vtkPolyData *grid)
{
double marks[4] = {0., 200., 400., 600.};
double thickness = 200.;
vtkNew<vtkPoints> points;
grid->SetPoints(points.Get());
for (int x_i = 0; x_i < 4; ++x_i)
{
for (int y_i = 0; y_i < 4; ++y_i)
{
points->InsertNextPoint(marks[x_i], marks[y_i], -thickness / 2.);
points->InsertNextPoint(marks[x_i], marks[y_i], +thickness / 2.);
}
}
std::vector<vtkIdType> quads;
for (vtkIdType col = 0; col < 4; ++col)
{
for (int row = 0; row < 3; ++row)
{
// Along y:
vtkIdType base = 8 * col + 2 * row;
quads.push_back(base + 0);
quads.push_back(base + 1);
quads.push_back(base + 3);
quads.push_back(base + 2);
}
}
vtkNew<vtkCellArray> cellArray;
grid->SetPolys(cellArray.Get());
for (size_t i = 0; i < quads.size(); i += 4)
{
grid->InsertNextCell(VTK_QUAD, 4, &quads[i]);
}
}
} // end namespace vtkTestBillboardTextActor3D
//----------------------------------------------------------------------------
int TestBillboardTextActor3D(int, char *[])
{
using namespace vtkTestBillboardTextActor3D;
vtkNew<vtkRenderer> ren;
ren->UseDepthPeelingOn();
int width = 600;
int height = 600;
int x[3] = {100, 300, 500};
int y[3] = {100, 300, 500};
// Render the anchor points to check alignment:
vtkNew<vtkPolyData> anchors;
vtkNew<vtkPoints> points;
anchors->SetPoints(points.GetPointer());
vtkNew<vtkCellArray> verts;
anchors->SetVerts(verts.GetPointer());
vtkNew<vtkUnsignedCharArray> colors;
colors->SetNumberOfComponents(4);
anchors->GetCellData()->SetScalars(colors.GetPointer());
for (size_t row = 0; row < 3; ++row)
{
for (size_t col = 0; col < 3; ++col)
{
vtkNew<vtkBillboardTextActor3D> actor;
switch (row)
{
case 0:
actor->GetTextProperty()->SetJustificationToRight();
break;
case 1:
actor->GetTextProperty()->SetJustificationToCentered();
break;
case 2:
actor->GetTextProperty()->SetJustificationToLeft();
break;
}
switch (col)
{
case 0:
actor->GetTextProperty()->SetVerticalJustificationToBottom();
break;
case 1:
actor->GetTextProperty()->SetVerticalJustificationToCentered();
break;
case 2:
actor->GetTextProperty()->SetVerticalJustificationToTop();
break;
}
actor->GetTextProperty()->SetFontSize(20);
actor->GetTextProperty()->SetOrientation(45.0 * (3 * row + col));
actor->GetTextProperty()->SetColor(0.75, .2 + col * .26, .2 + row * .26);
actor->GetTextProperty()->SetBackgroundColor(0.,
1. - col * .26,
1. - row * .26);
actor->GetTextProperty()->SetBackgroundOpacity(0.85);
actor->SetPosition(x[col], y[row], 0.);
setupBillboardTextActor3D(actor.GetPointer(), anchors.GetPointer());
ren->AddActor(actor.GetPointer());
}
}
vtkNew<vtkPolyDataMapper> anchorMapper;
anchorMapper->SetInputData(anchors.GetPointer());
vtkNew<vtkActor> anchorActor;
anchorActor->SetMapper(anchorMapper.GetPointer());
anchorActor->GetProperty()->SetPointSize(5);
ren->AddActor(anchorActor.GetPointer());
// Add some various 'empty' actors to make sure there are no surprises:
vtkNew<vtkBillboardTextActor3D> nullInputActor;
nullInputActor->SetInput(NULL);
ren->AddActor(nullInputActor.GetPointer());
vtkNew<vtkBillboardTextActor3D> emptyInputActor;
emptyInputActor->SetInput("");
ren->AddActor(emptyInputActor.GetPointer());
vtkNew<vtkBillboardTextActor3D> spaceActor;
spaceActor->SetInput(" ");
ren->AddActor(spaceActor.GetPointer());
vtkNew<vtkBillboardTextActor3D> tabActor;
tabActor->SetInput("\t");
ren->AddActor(tabActor.GetPointer());
vtkNew<vtkBillboardTextActor3D> newlineActor;
newlineActor->SetInput("\n");
ren->AddActor(newlineActor.GetPointer());
vtkNew<vtkPolyData> grid;
setupGrid(grid.Get());
vtkNew<vtkPolyDataMapper> gridMapper;
gridMapper->SetInputData(grid.Get());
vtkNew<vtkActor> gridActor;
gridActor->GetProperty()->SetRepresentationToSurface();
gridActor->GetProperty()->SetColor(0.6, 0.6, 0.6);
gridActor->SetMapper(gridMapper.Get());
ren->AddActor(gridActor.Get());
vtkNew<vtkRenderWindow> win;
win->AddRenderer(ren.GetPointer());
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(win.GetPointer());
ren->SetBackground(0.0, 0.0, 0.0);
ren->GetActiveCamera()->SetPosition(width/2, height/2, 1400);
ren->GetActiveCamera()->SetFocalPoint(width/2, height/2, 0);
ren->GetActiveCamera()->SetViewUp(0, 1, 0);
ren->GetActiveCamera()->Roll(45.);
ren->GetActiveCamera()->Elevation(45.);
ren->ResetCameraClippingRange();
win->SetSize(width, height);