indexing description: "[ 3D counterpart to EM_TTF_FONT that provides Em3d with font rendering capabilities. ]" author: "" date: "$Date$" revision: "$Revision$" class EM3D_TTF_FONT inherit EM3D_FONT EM_CONSTANTS export {NONE} all end EMGL_VIEW export {NONE} all end EMGLU_VIEW export {NONE} all end EMGL_SETTINGS export {NONE} all end EMGL_BASIC_RENDERER export {NONE} all end create {EM3D_FONT_FACTORY} make_from_ttf feature {NONE} -- Initialization make_from_ttf (a_ttf_font: EM_TTF_FONT) is -- Initialize `Current'. require font_not_void: a_ttf_font /= Void local i: INTEGER do font := a_ttf_font create glyph_cache.make (0, 255) from i := 0 until i > 255 loop glyph_cache[i] := Void i := i + 1 end ensure set: font = a_ttf_font end feature -- Basic operations cache_string (a_string: STRING) is -- local i: INTEGER g: EM3D_TTF_GLYPH do from i := 1 until i > a_string.count loop g := glyph ((a_string @ i).code) check g /= Void end i := i + 1 end end render_string (a_string: STRING; a_pos: EM_VECTOR3D; a_point_size: DOUBLE; a_color: EM_COLOR) is -- Render `a_string' at `a_pos', using current font with `a_point_size' and `a_color' -- subject to all OpenGL transformations. -- `a_pos' is start of the baseline. -- This implies that the OpenGL modelview and projection matrices -- are set to an appropriate transformation. -- Something like gluOrtho (0, w, h, 0) should give the expected -- results with regard to the 2D equivalent of this function: -- {EM_TTF_FONT}.draw_string -- The modelview transformation can also easily be set using -- {EM_COORDINATE_FRAME} local s: DOUBLE do emgl_matrix_mode (em_gl_modelview) emgl_push_matrix emgl_translated (a_pos.x, a_pos.y, a_pos.z) s := a_point_size / optimal_point_size emgl_scaled (s, s, s) -- Draw render_string_impl (a_string, a_color) emgl_pop_matrix end render_string_point_snapped (a_string: STRING; a_pos: EM_VECTOR3D; a_point_size: DOUBLE; a_color: EM_COLOR) is -- Same as `render_string', but tries to render `a_string' at integral coordinates to -- achieve better visual quality. local s: DOUBLE do emgl_push_matrix -- Round to integer coordinates emgl_translated (a_pos.x.rounded, a_pos.y.rounded, a_pos.z) s := a_point_size / optimal_point_size emgl_scaled (s, s, s) -- Draw render_string_impl (a_string, a_color) emgl_pop_matrix end feature -- Measurements optimal_point_size: DOUBLE is -- Point size of the internally used ttf-font do Result := font.point_size.to_double end line_skip (a_point_size: DOUBLE): DOUBLE is -- Recommended line spacing for `a_point_size' do Result := scale (font.font_line_skip, a_point_size) end ascent (a_point_size: DOUBLE): DOUBLE is --Max ascent for `a_point_size' do Result := scale (font.font_ascent, a_point_size) end descent (a_point_size: DOUBLE): DOUBLE is -- Max descent for `a_point_size' do Result := scale (font.font_descent, a_point_size) end baseline_offset (a_point_size: DOUBLE): DOUBLE is -- Offset of baseline from top boundary for `a_point_size' do -- Gives best results. Tried adding bias to account for -- line skip, but result was not pleasing Result := ascent (a_point_size) end char_width (a_chr: CHARACTER; a_point_size: DOUBLE): DOUBLE is -- Width of `a_chr' for `a_point_size' do -- This also buffers the character texture -- One can argue whether this is a good or a bad thing... -- Personally, I think it is good. If we're interested -- in the metrics of a character, we're probably going -- to render it, anyway. Result := scale (glyph (a_chr.code).metrics.advance, a_point_size) end string_width (a_string: STRING; a_point_size: DOUBLE): DOUBLE is -- Width of `a_string' for `a_point_size' local i: INTEGER sx: DOUBLE do sx := 0.0 -- Cannot use font.string_width because we have no kerning available -- when rendering glyphs seperately from i := 1 until i > a_string.count loop sx := sx + glyph ((a_string @ i).code).metrics.advance i := i + 1 end Result := scale (sx, a_point_size) end string_height (a_string: STRING; a_point_size: DOUBLE): DOUBLE is -- Height of `a_string' for `a_point_size' (single line always) do Result := line_skip (a_point_size) end feature {NONE} -- Implementation render_string_impl (a_string: STRING; a_color: EM_COLOR) is -- Render `a_string' with `a_color', assuming that transformation has -- already been set up. local i: INTEGER do emgl_push_attrib (em_gl_color_buffer_bit | em_gl_depth_buffer_bit | em_gl_enable_bit) emgl_depth_mask (em_gl_false) emgl_disable (em_gl_cull_face) emgl_enable (em_gl_blend) emgl_blend_func (em_gl_src_alpha, em_gl_one_minus_src_alpha) emgl_enable (em_gl_texture_2d) emgl_color4ub (a_color.red, a_color.green, a_color.blue, a_color.alpha) emgl_normal3d (0.0, 0.0, -1.0) from i := 1 until i > a_string.count loop glyph ((a_string @ i).code).render i := i + 1 end emgl_pop_attrib end scale (fm: DOUBLE; a_point_size: DOUBLE): DOUBLE -- Scale `fm' from `optimal_point_size' to `a_point_size' do Result := fm * a_point_size / optimal_point_size end font: EM_TTF_FONT -- 2D counterpart glyph_cache: ARRAY [EM3D_TTF_GLYPH] -- Cache that stores glyphs for rendering glyph (code: INTEGER): EM3D_TTF_GLYPH is -- Return glyph associated with `code' require valid_index: glyph_cache.lower <= code and code <= glyph_cache.upper local g: EM3D_TTF_GLYPH do g := glyph_cache[code] if g = Void then create g.make (code, font) glyph_cache[code] := g end Result := g end invariant properly_initialized: font /= Void and glyph_cache /= Void end