Chapter 5. The Font Engine

 This chapter gives you an overview of the font engine and describes how you can make use of Heidi font capabilities.


mx_fontengine = (HT_Create_Font_Engine)
    HD_Load_Dynamic_Routine("gdifont10.hdi","HD_Font_Engine");
      Note: The font engine now works with any Heidi renderer.

      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);
       3. Choose a font and make it the current font:
    m_font_engine.load_font(m_font);
        4. Draw text in the current font with your favorite text attributes:
    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:

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; }
};
// 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;}
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.