Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

482 lines
13 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkOpenGLFreeTypeTextMapper.cxx,v $
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 "vtkOpenGLFreeTypeTextMapper.h"
#include "vtkActor2D.h"
#include "vtkObjectFactory.h"
#include "vtkProperty2D.h"
#include "vtkTextProperty.h"
#include "vtkViewport.h"
#include "vtkWindow.h"
#include "vtkToolkits.h" // for VTK_USE_GL2PS
#include "vtkFreeTypeUtilities.h"
#include "vtkftglConfig.h"
#include "vtkgluPickMatrix.h"
#include "FTFont.h"
#ifdef VTK_USE_GL2PS
#include "gl2ps.h"
#endif // VTK_USE_GL2PS
//----------------------------------------------------------------------------
// Print debug info
#define VTK_FTTM_DEBUG 0
#define VTK_FTTM_DEBUG_CD 0
//----------------------------------------------------------------------------
// GL2PS related internal helper functions.
#ifdef VTK_USE_GL2PS
static void
vtkOpenGLFreeTypeTextMapper_GetGL2PSFontName(vtkTextProperty *tprop,
char *ps_font)
{
// For speed we use ARIAL == 0, COURIER == 1, TIMES == 2
static char const *family[] = {"Helvetica", "Courier", "Times"};
static char const *italic[] = {"Oblique", "Oblique", "Italic"};
static char const *base[] = {"", "", "-Roman"};
int font = tprop->GetFontFamily();
if (font > 2)
{
sprintf(ps_font, "%s", tprop->GetFontFamilyAsString());
if (tprop->GetBold())
{
sprintf(ps_font, "%s%s", ps_font, "Bold");
}
if (tprop->GetItalic())
{
sprintf(ps_font, "%s%s", ps_font, "Italic");
}
return;
}
if (tprop->GetBold())
{
sprintf(ps_font, "%s-%s", family[font], "Bold");
if (tprop->GetItalic())
{
sprintf(ps_font, "%s%s", ps_font, italic[font]);
}
}
else if (tprop->GetItalic())
{
sprintf(ps_font, "%s-%s", family[font], italic[font]);
}
else
{
sprintf(ps_font, "%s%s", family[font], base[font]);
}
}
#endif
//----------------------------------------------------------------------------
#ifndef VTK_IMPLEMENT_MESA_CXX
vtkCxxRevisionMacro(vtkOpenGLFreeTypeTextMapper, "$Revision: 1.45 $");
vtkStandardNewMacro(vtkOpenGLFreeTypeTextMapper);
#endif
//----------------------------------------------------------------------------
vtkOpenGLFreeTypeTextMapper::vtkOpenGLFreeTypeTextMapper()
{
this->LastSize[0] = 0;
this->LastSize[1] = 0;
}
//----------------------------------------------------------------------------
vtkOpenGLFreeTypeTextMapper::~vtkOpenGLFreeTypeTextMapper()
{
if (this->LastWindow)
{
this->ReleaseGraphicsResources(this->LastWindow);
}
}
//----------------------------------------------------------------------------
void vtkOpenGLFreeTypeTextMapper::ReleaseGraphicsResources(vtkWindow *vtkNotUsed(win))
{
#if VTK_FTTM_DEBUG
printf("vtkOpenGLFreeTypeTextMapper::ReleaseGraphicsResources\n");
#endif
this->LastWindow = NULL;
// Very important
// the release of graphics resources indicates that significant changes have
// occurred. Old fonts, cached sizes etc are all no longer valid, so we send
// ourselves a general modified message.
// this->Modified();
}
//----------------------------------------------------------------------------
void vtkOpenGLFreeTypeTextMapper::GetSize(vtkViewport* viewport, int *size)
{
// Check for multiline
if (this->NumberOfLines > 1)
{
this->GetMultiLineSize(viewport, size);
return;
}
// Check for input
if (this->Input == NULL || this->Input[0] == '\0')
{
size[0] = size[1] = 0;
return;
}
vtkTextProperty *tprop = this->GetTextProperty();
if (!tprop)
{
vtkErrorMacro(<< "Need a text property to get size");
size[0] = size[1] = 0;
return;
}
// Check to see whether we have to rebuild anything
if (this->GetMTime() < this->SizeBuildTime &&
tprop->GetMTime() < this->SizeBuildTime)
{
#if VTK_FTTM_DEBUG
printf("vtkOpenGLFreeTypeTextMapper::GetSize: In cache!\n");
#endif
size[0] = this->LastSize[0];
size[1] = this->LastSize[1];
return;
}
// Check for font and try to set the size
vtkFreeTypeUtilities::Entry *entry =
vtkFreeTypeUtilities::GetInstance()->GetFont(tprop);
FTFont *font = entry ? entry->Font : NULL;
if (!font)
{
vtkErrorMacro(<< "Render - No font");
size[0] = size[1] = 0;
return;
}
// The font global ascender and descender might just be too high
// for given a face. Let's get a compromise by computing these values
// from some usual ascii chars.
if (entry->LargestAscender < 0 || entry->LargestDescender < 0)
{
float llx, lly, llz, urx, ury, urz;
font->BBox("_/7Agfy", llx, lly, llz, urx, ury, urz);
entry->LargestAscender = ury;
entry->LargestDescender = lly;
}
this->LastSize[0] = size[0] = (int)font->Advance(this->Input);
this->LastSize[1] = size[1] =
(int)(entry->LargestAscender - entry->LargestDescender);
this->LastLargestDescender = (int)entry->LargestDescender;
this->SizeBuildTime.Modified();
}
//----------------------------------------------------------------------------
void vtkOpenGLFreeTypeTextMapper::RenderOverlay(vtkViewport* viewport,
vtkActor2D* actor)
{
vtkDebugMacro (<< "RenderOverlay");
// Check for input
if (this->Input == NULL || this->Input[0] == '\0')
{
return;
}
// Check for multi-lines
if (this->NumberOfLines > 1)
{
this->RenderOverlayMultipleLines(viewport, actor);
return;
}
// Get text property
vtkTextProperty *tprop = this->GetTextProperty();
if (!tprop)
{
vtkErrorMacro(<< "Need a text property to render mapper");
return;
}
// Get the window information for display
vtkWindow* window = viewport->GetVTKWindow();
if (this->LastWindow && this->LastWindow != window)
{
this->ReleaseGraphicsResources(this->LastWindow);
}
this->LastWindow = window;
// Get size of text
int size[2];
this->GetSize(viewport, size);
// Get the position of the text actor
int* actorPos;
actorPos=
actor->GetActualPositionCoordinate()->GetComputedViewportValue(viewport);
// Define bounding rectangle
int pos[2];
pos[0] = actorPos[0];
pos[1] = (int)(actorPos[1] - tprop->GetLineOffset());
switch (tprop->GetJustification())
{
case VTK_TEXT_LEFT:
break;
case VTK_TEXT_CENTERED:
pos[0] = pos[0] - size[0] / 2;
break;
case VTK_TEXT_RIGHT:
pos[0] = pos[0] - size[0];
break;
}
switch (tprop->GetVerticalJustification())
{
case VTK_TEXT_TOP:
pos[1] = pos[1] - size[1] - this->LastLargestDescender;
break;
case VTK_TEXT_CENTERED:
pos[1] = pos[1] - size[1] / 2 - this->LastLargestDescender / 2;
break;
case VTK_TEXT_BOTTOM:
break;
}
// Push a 2D matrix on the stack
int *vsize = viewport->GetSize();
double *vport = viewport->GetViewport();
double *tileViewport = viewport->GetVTKWindow()->GetTileViewport();
double visVP[4];
visVP[0] = (vport[0] >= tileViewport[0]) ? vport[0] : tileViewport[0];
visVP[1] = (vport[1] >= tileViewport[1]) ? vport[1] : tileViewport[1];
visVP[2] = (vport[2] <= tileViewport[2]) ? vport[2] : tileViewport[2];
visVP[3] = (vport[3] <= tileViewport[3]) ? vport[3] : tileViewport[3];
if (visVP[0] == visVP[2] || visVP[1] == visVP[3])
{
return;
}
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
if(viewport->GetIsPicking())
{
vtkgluPickMatrix(viewport->GetPickX(), viewport->GetPickY(),
1, 1, viewport->GetOrigin(), viewport->GetSize());
}
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_LIGHTING);
glDepthFunc(GL_ALWAYS);
if (actor->GetProperty()->GetDisplayLocation() == VTK_FOREGROUND_LOCATION)
{
glOrtho(0, vsize[0] - 1, 0, vsize[1] - 1, 0, 1);
}
else
{
glOrtho(0, vsize[0] - 1, 0, vsize[1] - 1, -1, 0);
}
int *winSize = viewport->GetVTKWindow()->GetSize();
int xoff = static_cast<int>(pos[0] - winSize[0] * (visVP[0] - vport[0]));
int yoff = static_cast<int>(pos[1] - winSize[1] * (visVP[1] - vport[1]));
// When picking draw the bounds of the text as a rectangle,
// as text only picks when the pick point is exactly on the
// origin of the text
if(viewport->GetIsPicking())
{
float x1 = 2.0 * (float)actorPos[0] / vsize[0] - 1;
float y1 = 2.0 * ((float)actorPos[1] - tprop->GetLineOffset())/vsize[1] - 1;
float width = 2.0 * (float)size[0] / vsize[0];
float height = 2.0 * (float)size[1] / vsize[1];
glRectf(x1, y1, x1 + width, y1 + height);
// Clean up and return after drawing the rectangle
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_LIGHTING);
glDepthFunc(GL_LEQUAL);
return;
}
double* tprop_color = tprop->GetColor();
double tprop_opacity = tprop->GetOpacity();
// Get the font
vtkFreeTypeUtilities::Entry *entry =
vtkFreeTypeUtilities::GetInstance()->GetFont(tprop, tprop_color);
FTFont *font = entry ? entry->Font : NULL;
if (!font)
{
vtkErrorMacro(<< "Render - No font");
return;
}
struct FTGLRenderContext *ftgl_context = 0;
#ifdef VTK_IMPLEMENT_MESA_CXX
// If we support Mangle Mesa, VTK_IMPLEMENT_MESA_CXX will be defined to
// compile this unit as a Mesa text mapper. In that case, provide a
// context to FTGL to switch dynamically to Mangle Mesa rendering.
struct FTGLRenderContext ftgl_context_mesa;
ftgl_context_mesa.UseMangleMesa = 1;
ftgl_context = &ftgl_context_mesa;
#endif
// Setup the fonts for GL2PS output.
#ifdef VTK_USE_GL2PS
char ps_font[64];
vtkOpenGLFreeTypeTextMapper_GetGL2PSFontName(tprop, ps_font);
#endif // VTK_USE_GL2PS
// Set up the shadow color
if (tprop->GetShadow())
{
double shadow_color[3], rgb;
rgb = ((tprop_color[0] + tprop_color[1] + tprop_color[2]) / 3.0 > 0.5)
? 0.0 : 1.0;
shadow_color[0] = shadow_color[1] = shadow_color[2] = rgb;
// Get the shadow font
vtkFreeTypeUtilities::Entry *shadow_entry =
vtkFreeTypeUtilities::GetInstance()->GetFont(tprop, shadow_color);
FTFont *shadow_font = shadow_entry ? shadow_entry->Font : NULL;
if (!shadow_font)
{
vtkErrorMacro(<< "Render - No shadow font");
return;
}
// Set the color here since load/render glyphs is done
// on demand and this color has to be consistent for a given font entry.
glColor4ub((unsigned char)(shadow_color[0] * 255.0),
(unsigned char)(shadow_color[1] * 255.0),
(unsigned char)(shadow_color[2] * 255.0),
(unsigned char)(tprop_opacity * 255.0));
// Required for clipping to work correctly
glRasterPos2i(0, 0);
glBitmap(0, 0, 0, 0,
xoff + tprop->GetShadowOffset()[0],
yoff + tprop->GetShadowOffset()[1], NULL);
// Draw the shadow text
shadow_font->render(this->Input, ftgl_context);
// Get the font again, Duh, since it may have been freed from the
// cache by the shadow font
font = vtkFreeTypeUtilities::GetInstance()->GetFont(
tprop, tprop_color)->Font;
if (!font)
{
vtkErrorMacro(<< "Render - No font");
return;
}
// Shadow text for GL2PS.
#ifdef VTK_USE_GL2PS
glRasterPos2i(xoff + tprop->GetShadowOffset()[0],
yoff + tprop->GetShadowOffset()[1]);
gl2psText(this->Input, ps_font, tprop->GetFontSize());
#endif // VTK_USE_GL2PS
}
// Set the color here since load/render glyphs is done
// on demand and this color has to be consistent for a given font entry.
glColor4ub((unsigned char)(tprop_color[0] * 255.0),
(unsigned char)(tprop_color[1] * 255.0),
(unsigned char)(tprop_color[2] * 255.0),
(unsigned char)(tprop_opacity * 255.0));
// Required for clipping to work correctly
glRasterPos2i(0, 0);
glBitmap(0, 0, 0, 0, xoff, yoff, NULL);
// Display a string
font->render(this->Input, ftgl_context);
glFlush();
// Normal text for GL2PS.
#ifdef VTK_USE_GL2PS
glRasterPos2i(xoff, yoff);
gl2psText(this->Input, ps_font, tprop->GetFontSize());
#endif // VTK_USE_GL2PS
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_LIGHTING);
glDepthFunc(GL_LEQUAL);
}
void vtkOpenGLFreeTypeTextMapper::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
}