This chapter gives you an overview of the font engine and describes how you can make use of Heidi font capabilities.
Following is a more detailed description of how to enable a font engine, from heidi_glue.cpp in samples\simpleNoMFC:
mx_fontengine = (HT_Create_Font_Engine)
HD_Load_Dynamic_Routine("gdifont10.hdi","HD_Font_Engine");
2. Find a font:
The Font Engine needs to be established.
Establish has always been available for renderers and now gives the Font
Engine an opportunity to be configured with the the options set on it.
Create a font description for the required font and call find_font.
find_font returns an HT_Font based on the descriptor.
// get the font engine going
m_font_engine = (*mx_fontengine)(m_render);
m_font_engine.establish();
HT_Font_Descriptor fd;
fd.set_name ("Arial");
m_font = m_font_engine.find_font (fd);
m_font_engine.load_font(m_font);
rend.set_font (m_font); if (m_font.scaleable()) rend.set_text_scale (25.0f);
rend.set_font (m_font); m_font_engine.draw_2d_text (rend, HT_DC_Point (500.0f,250.0f,0.0f), "Colorized Polytriangle");
After the text is drawn, the unload_font
method is used to remove the fonts.
API
The Heidi font API consists
of the following three basic parts:
The Font Engine
The font engine is loaded directly with Heidi's DLL-loading
mechanism. The font engine is accessible through a pointer to HT_Font_Engine.
Here is the class definition from the file font_engine.h in source\heidi\font.
Unless you plan to write a Heidi font engine, like most application programmers,
you need only familiarize yourself with the access methods.
Note: In order for the font engine to take into
effect the set configurations, the clients of the font engine need to call
establish().
establish()
in turn does the appropriate configurations necessary and calls establish_configuration().
The addition of the establish call
int establish (void) alter { return modify().establish();
public:
HT_Font_Engine (){}
HT_Font_Engine (HT_Font_Engine_Data const * in)
: m_data (in) {}
// current and configuration access methods
HT_Option const * option (HT_String const & name) const {
return read().option (name);
}
HT_Option_Value option_value (HT_String const & name) const {
return read().option_value (name);
}
HT_Boolean set_option_value (HT_String const & name,
HT_Option_Value const & value) alter {
return modify().set_option_value (name, value);
}
HT_Counted const * attachment () const { return read().attachment();}
void set_attachment (HT_Counted * in) {modify().set_attachment(in);}
int establish (void) alter { return modify().establish(); }
// search path management
void add_dir (char *x) {modify().add_dir(x);}
HT_Directory * first_dir (HT_Position & p) {return modify().first_dir(p);}
HT_Directory * next_dir (HT_Position & p) {return modify().next_dir(p);}
HT_Directory * dir (HT_Position p) {return modify().dir(p);}
HT_Position add_font (HT_Font const & x) {return modify().add_font(x);}
HT_Font const & first_font (HT_Position & p) {return modify().first_font(p);}
HT_Font const & next_font (HT_Position & p) {return modify().next_font(p);}
HT_Font const & font (HT_Position p) {return modify().font(p);}
HT_Renderer const & renderer() const {return read().renderer();}
void set_renderer (HT_Renderer const & in_renderer) alter
{modify().set_renderer (in_renderer);}
// access to virtuals
HT_Font load_font(HT_Font alter & x) {return modify().load_font(x);}
HT_Boolean font_loaded (HT_Font const & x) const {return read().font_loaded(x);}
HT_Boolean unload_font (HT_Font alter & x) {return modify().unload_font(x);}
HT_Font find_font (HT_Font_Descriptor const & x)
{return modify().find_font(x);}
HT_Font find_font (HT_Font_Descriptor const & x, HT_Position & p)
{return modify().find_font(x, p);}
HT_Boolean find_glyph (HT_Rendition const & hr, unsigned short glyph)
{ return modify().find_glyph(hr, glyph); }
void draw_2d_text (
HT_Rendition const & hr,
HT_Point const & pos,
char const * str) alter {
modify().draw_2d_text (hr, pos, str);
}
void draw_2d_text (
HT_Rendition const & hr,
HT_Point const & pos,
char const * str,
float const * char_spacing) alter {
if (char_spacing == null)
modify().draw_2d_text (hr, pos, str);
else
modify().draw_2d_text (hr, pos, str, char_spacing);
}
void draw_2d_text (
HT_Rendition const & hr,
HT_Point const & pos,
char const * str,
int count) alter {
modify().draw_2d_text (hr, pos, str, count);
}
void draw_2d_text (
HT_Rendition const & hr,
HT_Point const & pos,
char const * str,
int count,
float const * char_spacing) alter {
if (char_spacing == null)
modify().draw_2d_text (hr, pos, str, count);
else
modify().draw_2d_text (hr, pos, str, count, char_spacing);
}
void draw_2d_text (
HT_Rendition const & hr,
HT_Point const & pos,
unsigned short const * str,
int count) alter {
modify().draw_2d_text (hr, pos, str, count);
}
void draw_2d_text (
HT_Rendition const & hr,
HT_Point const & pos,
unsigned short const * str,
int count,
float const * char_spacing) alter {
if (char_spacing == null)
modify().draw_2d_text (hr, pos, str, count);
else
modify().draw_2d_text (hr, pos, str, count, char_spacing);
}
void draw_3d_text (
HT_Rendition const & hr,
HT_Point const & pos,
char const * str) alter {
modify().draw_3d_text (hr, pos, str);
}
void draw_3d_text (
HT_Rendition const & hr,
HT_Point const & pos,
char const * str,
int count) alter {
modify().draw_3d_text (hr, pos, str, count);
}
void draw_3d_text (
HT_Rendition const & hr,
HT_Point const & pos,
unsigned short const * str,
int count) alter {
modify().draw_3d_text (hr, pos, str, count);
}
void get_text_extent (
HT_Rendition const & hr,
HT_Point const & pos,
char const * str,
HT_Point * result,
HT_Boolean tight_extents=HK_False,
HT_Extent_Metrics * extent_metrics=null) alter {
modify().get_text_extent (hr, pos, str, result, tight_extents, extent_metrics);
}
void get_text_extent (
HT_Rendition const & hr,
HT_Point const & pos,
char const * str,
int count,
HT_Point * result,
HT_Boolean tight_extents=HK_False,
HT_Extent_Metrics * extent_metrics=null) alter {
modify().get_text_extent (hr, pos, str, count, result, tight_extents, extent_metrics);
}
void get_text_extent (
HT_Rendition const & hr,
HT_Point const & pos,
unsigned short const * str,
int count,
HT_Point * result,
HT_Boolean tight_extents=HK_False,
HT_Extent_Metrics * extent_metrics=null) alter {
modify().get_text_extent (hr, pos, str, count, result, tight_extents, extent_metrics);
}
// The following function is obsolete. It's only here so that existing applications
// making used of this does not break. The new API does not take resolution. Resolution
// is now set as an option on the font engine.
HT_Contour_Set get_char_outline (
HT_Rendition const & hr,
unsigned short uchar,
int resolution,
HT_Glyph_Metrics * gm) alter {
return modify().get_char_outline (hr, uchar, resolution, gm);
}
HT_Contour_Set get_char_outline (
HT_Rendition const & hr,
unsigned short uchar,
HT_Glyph_Metrics * gm) alter {
return modify().get_char_outline (hr, uchar, gm);
}
void get_font_design_metrics (
HT_Rendition const & hr,
HT_Font_Metrics * fm) alter {
modify().get_font_design_metrics (hr, fm);
}
void get_font_metrics (
HT_Rendition const & hr,
HT_Font_Metrics * fm) alter {
modify().get_font_metrics (hr, fm);
}
void get_character_placement (
HT_Rendition const & hr,
unsigned short const * str,
int count,
float * spacing) alter {
modify().get_character_placement (hr, str, count, spacing);
}
void get_character_widths (
HT_Rendition const & hr,
unsigned short first_char,
unsigned short last_char,
float * width) alter {
modify().get_character_widths (hr, first_char, last_char, width);
}
};
// wrapper class around counted font pointer, for external use
class HT_Font {
protected:
HT_Pointer<HT_Font_Data> m_data;
HANDLE_CLASS_BASIC_FUNCTIONS (HT_Font, HT_Font_Data);
HEIDI_API void create_empty_data (void);
void validate (void) { if (m_data == null) create_empty_data ();}
#if defined(HEIDI_PANOSE_AVAILABLE)
void set_panose1(HT_Panose p) { m_data.modify().m_font_desc.set_panose1(p); }
#endif
HEIDI_API void set_name(char const * in);
void set_bold (HT_Boolean in) { validate(); m_data.modify().m_font_desc.set_bold(in); }
void set_italic (HT_Boolean in) { validate(); m_data.modify().m_font_desc.set_italic(in); }
void set_underlined (HT_Boolean in) { validate(); m_data.modify().m_font_desc.set_underlined(in); }
void set_font_type (HT_Font_Type in) { validate(); m_data.modify().m_font_desc.set_font_type(in); }
void set_charset (int in) { validate(); m_data.modify().m_font_desc.set_charset(in); }
void set_pitch_and_family (int in) { validate(); m_data.modify().m_font_desc.set_pitch_and_family(in); }
void set_size (float in) { validate(); m_data.modify().m_font_desc.set_size(in); }
void set_flags (HT_Font_Flags in) { validate(); m_data.modify().m_font_desc.set_flags(in); }
HEIDI_API void set_full_name(char const * in);
void set_creator (void * creator) { validate(); m_data.modify().m_creator = creator;}
void set_scaleable (HT_Boolean in) { validate(); m_data.modify().m_scaleable = in; }
void set_slantable (HT_Boolean in) { validate(); m_data.modify().m_slantable = in; }
void set_boldable (HT_Boolean in) { validate(); m_data.modify().m_boldable = in; }
void set_proportional (HT_Boolean in) { validate(); m_data.modify().m_proportional = in; }
void set_rotate_mode(int in) { validate(); m_data.modify().m_rotate_mode = in; }
public:
HT_Font_Descriptor font_descriptor(void) const { return read().m_font_desc; }
#if defined(HEIDI_PANOSE_AVAILABLE)
HT_Panose panose1() const { return read().m_font_desc.panose1(); }
#endif
char * name() const { return read().m_font_desc.name(); }
HT_Boolean bold () const { return read().m_font_desc.bold(); }
HT_Boolean italic () const { return read().m_font_desc.italic(); }
HT_Boolean underlined () const { return read().m_font_desc.underlined(); }
HT_Font_Type font_type () const { return read().m_font_desc.font_type(); }
int charset () const { return read().m_font_desc.charset(); }
int pitch_and_family () const { return read().m_font_desc.pitch_and_family(); }
float size () const { return read().m_font_desc.size(); }
HT_Font_Flags flags() const { return read().m_font_desc.flags(); }
char * full_name() const { return read().m_full_name; }
void * creator(void) const {return read().m_creator;}
HT_Boolean scaleable () const { return read().m_scaleable; }
HT_Boolean slantable () const { return read().m_slantable; }
HT_Boolean boldable () const { return read().m_boldable; }
HT_Boolean proportional () const { return read().m_proportional; }
int rotate_mode() const { return read().m_rotate_mode; }
};
The Text Rendition
The text rendition affects how text is drawn. As has
been demonstrated, the font object is one of the text attributes. In
addition to the font object, the text rendition has other text attribute
access methods, as shown in the following example from the file rendition.h
in heidi\source\heidi\rendition. Unless you plan to write a Heidi
font engine, like most application programmers, you need only familiarize
yourself with the access methods.
// text attributes
int
//Font_Draw_Modes
text_draw_mode () const
{return m_nr->m_text->m_draw_mode;}
void
set_text_draw_mode (int /* Font_Draw_Modes */ x,
HT_Boolean shared = HK_False) alter
{if (m_nr->m_text->m_draw_mode != x) wxr(shared).
m_draw_mode = x;}
float
text_spacing () const
{return m_nr->m_text->m_spacing;}
void
set_text_spacing (float x,
HT_Booleanshared = HK_False) alter
{if (m_nr->m_text->m_spacing != x)
wxr(shared).m_spacing = x;}
HT_Vector const &
text_path () const
{return m_nr->m_text->m_path;}
void
set_text_path(HT_Vector &x,
HT_Boolean shared = HK_False) alter
{wxr(shared).m_path = x;}
float
text_rotation () const
{return m_nr->m_text->m_rotation;}
void
set_text_rotation (float x,
HT_Boolean shared = HK_False) alter
{if (m_nr->m_text->m_rotation != x)
wxr(shared).m_rotation = x;}
float
text_scale () const
{return m_nr->m_text->m_scale;}
void
set_text_scale (float x,
HT_Boolean shared = HK_False) alter
{if (m_nr->m_text->m_scale != x)
wxr(shared).m_scale = x;}
HT_Font font () const
{return m_nr->m_text->m_font;}
void
set_font (HT_Font const & in_font,
HT_Boolean shared = HK_False)
{if (m_nr->m_text->m_font != in_font)
wxr(shared).m_font = in_font;}
Most other fields are self-explanatory. The rotation, and scalefields are the values supplied by a font engine that can rotate, slant, or scale a font at draw time.
Example
Following is an example of code using a font engine from
the file heidi_glue.cpp in samples\simpleNoMFC:
void Ex_Heidi::Draw_Scene() {
stack HT_Rendition rend(m_render);
stack HT_Rendition rend1(m_device);
stack HT_Point bounds[5];
stack char text[80];
strcpy (text,"Click On Demos");
m_device.begin_picture();
m_render.begin_picture();
m_render.clear_z_buffer (rend);
rend.set_background_color(HT_RGB32 (0xcf, 0xdf, 0x0F));
m_render.clear_drawing_buffer (rend);
m_render.update();
m_font_engine.set_renderer (m_render);
rend1.set_color(HT_RGB32 (0x0F, 0x0F, 0x0F));
if (m_gdi_font.scaleable())
rend1.set_text_scale (40.0f);
rend1.set_font (m_gdi_font);
m_font_engine.get_text_extent (rend1, HT_DC_Point
(300.0f,300.0f,0.0f), text, bounds, NULL);
bounds[4] = bounds[0];
m_render.draw_2d_polyline (rend1, 5, bounds);
m_font_engine.draw_2d_text (rend1, HT_DC_Point
(300.0f,300.0f,0.0f), text );
m_render.update();
m_render.end_picture();
m_device.update();
m_device.end_picture();
}
Drawing Text as Geometry ¾ HT_Renderer::draw_2d/3d_text
The HT_Renderer::draw_3d_text and draw_2d_text actions draw text similar to other geometry, instead of directly calling the Font Engine.The result of the default actions is the same as if you directly called the draw functions on the Font_Engine. In the default implementation the HT_Renderer::draw_3d_text action transforms the point and calls the HT_Renderer::draw_2d_text action. The (float) 2d_text converts to int and calls the int version of 2d_text. The int version then calls out to the Font_Engine associated with the font on the Rendition.
This new scheme allows a renderer to replace the text actions and treat text as just another piece of geometry. For example, a renderer that stores geometry and replays it back later (that is, sorted by position, or multiple times for banded plotting) no longer needs to have special code to deal with text or force tessellation of text into "simple" geometry for storage.
HT_Text is a new class with a different constructor to handle a single or double precision position, and either normal chars, with optional length, or wide chars ¾ unsigned short.