/*
								+--------------------------------+
								|                                |
								|  ***  OpenGL bitmap font  ***  |
								|                                |
								|  Copyright © -tHE SWINe- 2010  |
								|                                |
								|         BitmapFont2.h          |
								|                                |
								+--------------------------------+
*/

#pragma once
#ifndef __BITMAP_FONT2_INCLUDED
#define __BITMAP_FONT2_INCLUDED

/**
 *	@file BitmapFont2.h
 *	@author -tHE SWINe-
 *	@brief a simple OpenGL bitmap font implementation
 *	@date 2010
 *
 *	@date 2012-02-20
 *
 *	Fixed CGLBitmapFont2::CTextureArrayBuilder by using CGLTexture::n_Target() instead
 *	of assuming one (2D array textures were emulated by 3D textures, changing target
 *	to true 3D textures made this code crash).
 *
 *	@date 2014-03-12
 *
 *	Added the possiblity to specify the metadata block blanking color.
 *
 *	Overhauled CGLBitmapFont2::Generate_Geometry() to have a single powerful function
 *	which is hard to call and a single easy to use function, using std::vertex and
 *	not requiring the caller to allocate anything. Removed a few functions that the old
 *	implementations might have been using, breaking compatibility with some of the old code.
 *
 *	Added CGLBitmapFont2::p_Texture_2D() for fonts, loaded using CGLBitmapFont2::Load_2D().
 *	Using CGLBitmapFont2::p_Texture() for 2D fonts (or vice versa using
 *	CGLBitmapFont2::p_Texture_2D() for texture array fonts) will result in assertion failure.
 *
 *	Fixed a primitive restart bug which occured when index offset was nonzero (the index
 *	offset was errorneously added to the primitive restart index).
 *
 *	@t_odo Finish writing documentation comments.
 *	@todo Write functions for text alignment (left, right, center, justify).
 *	@todo Write composite functions for color text output or multiple fonts / multiple size text output.
 *	@todo Handle texture switching for multiple fonts (either merge textures to a
 *		bigger texture array or generate texture switch table, sort the index buffers accordingly).
 *	@todo std::strings, anyone? it is better to call Generate_Geometry() with &str[0], &str[0] + str.length()
 *		rather than with str.c_str(), this might not be obvious to the users.
 *	@todo Write creation as copying of data from CBitmapFont to a texture,
 *		that is the simplest and supports the widest number of possibilities.
 *	@todo Support image processing in creation.
 *	@todo Support 2D in creation.
 *
 */

/**
 *	@def __BITMAP_FONT_GLES20
 *	@brief if defined, OpenGL ES 2.0 is used as the
 *		OpenGL implementation (otherwise OpenGL 4.0 is used)
 */
#define __BITMAP_FONT_GLES20

/**
 *	@def __GLFONT_PRECRUNCH_GLYPH_GEOMETRY
 *	@brief if defined, font geometry is preprocessed after loading, instead of on-the-fly
 */
#define __GLFONT_PRECRUNCH_GLYPH_GEOMETRY

#include "FontTexture2.h"

#ifdef __BITMAP_FONT_GLES20
#ifdef __HAVE_GLES
#include "gles2/GLES20.h"
#else // __HAVE_GLES
#include "gles2/GLES20Emu.h"
#endif // __HAVE_GLES
#include "gles2/Texture.h"
#include "gles2/TextureUtil.h"
typedef CGLESTextureLoader CGLTextureLoader;
#else // __BITMAP_FONT_GLES20
#include "gl4/OpenGL40.h"
#include "gl4/Texture.h"
#include "gl4/TextureUtil.h"
#endif // __BITMAP_FONT_GLES20

/**
 *	@brief second generation OpenGL bitmap font
 */
class CGLBitmapFont2 {
public:
	/**
	 *	@brief character info lookup
	 */
	class CCharacterMap {
	public:
		/**
		 *	@brief configuration, stored as enums
		 */
		enum {
			direct_lookup_Size = 128 /**< @brief size of the direct (O(1) time) lookup table */
		};

	protected:
		bitmapfont2::TGlyphInfo m_t_lookup[direct_lookup_Size]; /**< @brief a small direct lookup of character code to character info */
		std::map<int, bitmapfont2::TGlyphInfo> m_char_map; /**< @brief map of character code to character info (only contains what did not fit in the direct lookup) */

	public:
		/**
		 *	@brief creates character map
		 *
		 *	@param[in] r_page_list is list of font page infos
		 *	@param[in] n_geom_padding is the value of geometry padding
		 *
		 *	@return Returns true on success, false on failure.
		 */
		bool Create(const CBitmapFont::CPageList &r_page_list, int n_geom_padding);

#ifdef __GLFONT_PRECRUNCH_GLYPH_GEOMETRY
		/**
		 *	@brief modifies geometry bounds by padding
		 *		(it is stored without padding, but rendered with it)
		 *
		 *	@param[in,out] r_t_info is glyph information
		 *	@param[in] n_geom_padding is the value of geometry padding
		 */
		static void PreCrunch(bitmapfont2::TGlyphInfo &r_t_info, int n_geom_padding);
#endif // __GLFONT_PRECRUNCH_GLYPH_GEOMETRY

		/**
		 *	@brief finds glyph information
		 *	@param[in] n_codepoint is character in UTF-32
		 *	@return Returns const pointer to the glyph information,
		 *		returns 0 in case the character is not supported by this font.
		 */
		const bitmapfont2::TGlyphInfo *p_Get_CharacterInfo(int n_codepoint) const;
	};

protected:
	template <class CPassTo>
	class CPassThroughBitmapWriter : public CBitmapFont::CBitmapWriter {
	protected:
		CPassTo &m_r_pass_to;

	public:
		CPassThroughBitmapWriter(const char *p_s_format, CPassTo &r_pass_to)
			:CBitmapWriter(p_s_format), m_r_pass_to(r_pass_to)
		{}

		virtual bool operator ()(size_t n_page, size_t n_page_num, const TBmp &r_t_bitmap)
		{
			if(!m_r_pass_to(n_page, n_page_num, r_t_bitmap))
				return false;
			// call pass-through

			return CBitmapWriter::operator ()(n_page, n_page_num, r_t_bitmap);
			// call bitmap writer
		}
	};

	class CTextureArrayBuilder : public CBitmapFont::CBitmapCallback {
	protected:
		GLenum m_n_internal_format;
		bool m_b_generate_mipmaps, m_b_use_npot;
		const CBitmapFont &m_r_bitmap_font;
		CGLTexture_2D_Array *m_p_texture;
		uint32_t m_n_blank_color;

	public:
		CTextureArrayBuilder(bool b_generate_mipmaps, GLenum n_internal_format,
			bool b_use_npot, const CBitmapFont &r_bitmap_font, uint32_t n_blank_color);

		/**
		 *	@copydoc CBitmapCallback::operator()()
		 */
		virtual bool operator ()(size_t n_page, size_t n_page_num, const TBmp &r_t_bitmap);

		inline CGLTexture_2D_Array *p_Get_Texture()
		{
			return m_p_texture;
		}
	};

	class CFakeTextureArrayBuilder : public CBitmapFont::CBitmapCallback {
	protected:
		GLenum m_n_internal_format;
		bool m_b_generate_mipmaps, m_b_use_npot;
		const CBitmapFont &m_r_bitmap_font;
		CGLTexture_2D *m_p_texture;
		uint32_t m_n_blank_color;

	public:
		CFakeTextureArrayBuilder(bool b_generate_mipmaps, GLenum n_internal_format,
			bool b_use_npot, const CBitmapFont &r_bitmap_font, uint32_t n_blank_color);

		/**
		 *	@copydoc CBitmapCallback::operator()()
		 */
		virtual bool operator ()(size_t n_page, size_t n_page_num, const TBmp &r_t_bitmap);

		inline CGLTexture_2D_Array *p_Get_Texture()
		{
			return (CGLTexture_2D_Array*)m_p_texture;
		}
	};

	bitmapfont2::TFontInfo m_t_font_info; /**< @brief font information structure */
	CCharacterMap m_character_map; /**< @brief glyph info lookup map */
	int m_n_replacement_char; /**< @brief the current replacement character (utf-32) */
	CGLTexture_2D_Array *m_p_texture; /**< @brief the font texture */
	GLenum m_n_mode; /**< @brief OpenGL draw mode (GL_TRIANGLES or GL_TRIANGLE_STRIP) */
	bool m_b_allow_degenerate; /**< @brief degenerate geometry flag (only for GL_TRIANGLE_STRIP) */
	uint32_t m_n_primitive_restart_index; /**< @brief primitive restart index (only for GL_TRIANGLE_STRIP) */
	int m_n_extra_vertex_element_num; /**< @brief number of vertices, preceding each vertex */

public:
	/**
	 *	@brief default constructor
	 */
	CGLBitmapFont2();

	/**
	 *	@brief destructor
	 */
	~CGLBitmapFont2();

	/**
	 *	@brief gets font information
	 *	@return Returns font information structure.
	 *	@note This only returns valid values after successful call to Create() or Load().
	 */
	inline const bitmapfont2::TFontInfo &t_Font_Info() const
	{
		return m_t_font_info;
	}

	/**
	 *	@brief determines whether the font texture is a 2D texture
	 *	@return Returns true if the font texture is a 2D texture,
	 *		false otherwise or if no font was loaded.
	 */
	inline bool b_Is_2D() const
	{
		return m_p_texture && b_IsTexture2D(m_p_texture->n_Target());
	}

	/**
	 *	@brief gets the font texture
	 *	@return Returns const pointer to the font texture.
	 */
	inline const CGLTexture_2D_Array *p_Texture() const
	{
		_ASSERTE(b_IsTexture3D(m_p_texture->n_Target()));
		return (b_IsTexture3D(m_p_texture->n_Target()))? m_p_texture : 0;
	}

	/**
	 *	@brief gets the font texture
	 *	@return Returns const pointer to the font texture.
	 *	@note This is for fonts, created with Load_2D().
	 */
	inline const CGLTexture_2D *p_Texture_2D() const
	{
		_ASSERTE(b_IsTexture2D(m_p_texture->n_Target()));
		return (b_IsTexture2D(m_p_texture->n_Target()))? (const CGLTexture_2D*)m_p_texture : 0;
	}

	/**
	 *	@brief creates a font with default font settings (contains only basic latin)
	 *
	 *	@param[in] p_s_font_face is font face
	 *	@param[in] n_font_size is font size in pixels
	 *	@param[in] b_generate_mipmaps is mip-map generation map (default false)
	 *	@param[in] n_internal_format is internal format (default GL_R8, or an equivalent 8-bit single-component)
	 *	@param[in] b_use_npot is non-power-of-two flag (if set, NPOT textures are used; default not set)
	 *	@param[in] p_s_store_filename is printf pattern to write the font to a file
	 *		(can be null; if set, the font is generated with metadata block and stored; default is null)
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note This sets replacement char to space (might not be present in the new font),
	 *		but does not modify the geometry generation settings.
	 */
	bool Create(const char *p_s_font_face, int n_font_size, bool b_generate_mipmaps = false,
		GLenum n_internal_format = CGLTextureLoader::n_Pixel_InternalFormat(1, 8, false),
		bool b_use_npot = false, const char *p_s_store_filename = 0);

	/**
	 *	@brief creates a new font
	 *
	 *	@param[in] p_s_font_face is font face
	 *	@param[in] n_font_size is font size in pixels
	 *	@param[in] r_bitmap_font is bitmap font object, containing the settings to create with
	 *	@param[in] b_generate_mipmaps is mip-map generation map (default false)
	 *	@param[in] n_internal_format is internal format (default GL_R8, or an equivalent 8-bit single-component)
	 *	@param[in] b_use_npot is non-power-of-two flag (if set, NPOT textures are used; default not set)
	 *	@param[in] p_s_store_filename is printf pattern to write the font to a file
	 *		(can be null; if set, the font is generated with metadata block and stored; default is null)
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note This sets replacement char to space (might not be present in the new font),
	 *		but does not modify the geometry generation settings.
	 */
	bool Create(const char *p_s_font_face, int n_font_size, CBitmapFont &r_bitmap_font,
		bool b_generate_mipmaps = false, GLenum n_internal_format =
		CGLTextureLoader::n_Pixel_InternalFormat(1, 8, false), bool b_use_npot = false,
		const char *p_s_store_filename = 0);

	/**
	 *	@brief loads font from a file
	 *
	 *	@param[in] p_s_filename is file name printf pattern
	 *	@param[in] b_generate_mipmaps is mip-map generation map (default false)
	 *	@param[in] n_internal_format is internal format (default GL_R8, or an equivalent 8-bit single-component)
	 *	@param[in] b_use_npot is non-power-of-two flag (if set, NPOT textures are used; default not set)
	 *	@param[in] n_blank_color is color the metadata block is cleared to and if NPOT is not used
	 *		also the color of the empty areas of the texture.
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note This sets replacement char to space (might not be present in the new font),
	 *		but does not modify the geometry generation settings.
	 */
	bool Load(const char *p_s_filename, bool b_generate_mipmaps = false,
		GLenum n_internal_format = CGLTextureLoader::n_Pixel_InternalFormat(1, 8, false),
		bool b_use_npot = false, uint32_t n_blank_color = 0);

	/**
	 *	@brief loads font from a bitmap producer
	 *
	 *	@param[in] r_bitmap_producer is source of the images
	 *	@param[in] b_generate_mipmaps is mip-map generation map (default false)
	 *	@param[in] n_internal_format is internal format (default GL_R8, or an equivalent 8-bit single-component)
	 *	@param[in] b_use_npot is non-power-of-two flag (if set, NPOT textures are used; default not set)
	 *	@param[in] n_blank_color is color the metadata block is cleared to and if NPOT is not used
	 *		also the color of the empty areas of the texture.
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note This sets replacement char to space (might not be present in the new font),
	 *		but does not modify the geometry generation settings.
	 */
	bool Load(CBitmapFont::CBitmapProducer &r_bitmap_producer, bool b_generate_mipmaps = false,
		GLenum n_internal_format = CGLTextureLoader::n_Pixel_InternalFormat(1, 8, false),
		bool b_use_npot = false, uint32_t n_blank_color = 0);

	/**
	 *	@brief loads 2D font from a file
	 *
	 *	2D fonts can only contain a single page. They can be used for rendering of fonts
	 *	with moderate amount of glyphs on devices that do not support 2D texture arrays.
	 *
	 *	@param[in] p_s_filename is file name printf pattern
	 *	@param[in] b_generate_mipmaps is mip-map generation map (default false)
	 *	@param[in] n_internal_format is internal format (default GL_R8, or an equivalent 8-bit single-component)
	 *	@param[in] b_use_npot is non-power-of-two flag (if set, NPOT textures are used; default not set)
	 *	@param[in] n_blank_color is color the metadata block is cleared to and if NPOT is not used
	 *		also the color of the empty areas of the texture.
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note This sets replacement char to space (might not be present in the new font),
	 *		but does not modify the geometry generation settings.
	 */
	bool Load_2D(const char *p_s_filename, bool b_generate_mipmaps = false,
		GLenum n_internal_format = CGLTextureLoader::n_Pixel_InternalFormat(1, 8, false),
		bool b_use_npot = false, uint32_t n_blank_color = 0);

	/**
	 *	@brief loads 2D font from a bitmap producer
	 *
	 *	2D fonts can only contain a single page. They can be used for rendering of fonts
	 *	with moderate amount of glyphs on devices that do not support 2D texture arrays.
	 *
	 *	@param[in] r_bitmap_producer is source of the images
	 *	@param[in] b_generate_mipmaps is mip-map generation map (default false)
	 *	@param[in] n_internal_format is internal format (default GL_R8, or an equivalent 8-bit single-component)
	 *	@param[in] b_use_npot is non-power-of-two flag (if set, NPOT textures are used; default not set)
	 *	@param[in] n_blank_color is color the metadata block is cleared to and if NPOT is not used
	 *		also the color of the empty areas of the texture.
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note This sets replacement char to space (might not be present in the new font),
	 *		but does not modify the geometry generation settings.
	 */
	bool Load_2D(CBitmapFont::CBitmapProducer &r_bitmap_producer, bool b_generate_mipmaps = false,
		GLenum n_internal_format = CGLTextureLoader::n_Pixel_InternalFormat(1, 8, false),
		bool b_use_npot = false, uint32_t n_blank_color = 0);

	/**
	 *	@brief sets generated primitive type
	 *
	 *	@param[in] n_mode is either GL_TRIANGLES or GL_TRIANGLE_STRIP
	 *	@param[in] b_allow_degenerate is degenerate flag (only applies on the triangle strip)
	 *	@param[in] n_primitive_restart is primitive restart vertex is (only applies on the
	 *		triangle strip if <tt>b_allow_degenerate</tt> is false)
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note The mode is preserved accross calls to Load(), Load_2D() or Create().
	 */
	bool Set_Mode(GLenum n_mode, bool b_allow_degenerate, int n_primitive_restart);

	/**
	 *	@brief sets replacement character
	 *
	 *	The replacement character is used for rendering characters that can not
	 *	be rendered using the current font (for example greek letter alpha can not
	 *	be rendered using basic latin fonts, and will be replaced by another character
	 *	that can be displayed (such as question mark, underscore or space)).
	 *
	 *	@param[in] n_replacement_char is replacement character in UTF-32 (space is default)
	 *	@return Returns true if the specified replacement character can be rendered
	 *		using the current font, otherwise returns false and the replacement character
	 *		remains unchanged.
	 */
	bool Set_ReplacementChar(int n_replacement_char);

	/**
	 *	@brief gets the current replacement character
	 *	@return Returns the current replacement character as UTF-32.
	 */
	inline int n_ReplacementChar() const
	{
		return m_n_replacement_char;
	}

	/**
	 *	@brief gets OpenGL primitive mode
	 *	@return Returns OpenGL primitive mode (GL_TRIANGLES or GL_TRIANGLE_STRIP).
	 */
	inline GLenum n_Primitive_Mode() const
	{
		return m_n_mode;
	}

	/**
	 *	@brief gets element array buffer requirement
	 *	@return Always returns true (element array buffer is required in all modes).
	 *	@note This is a part of geometry generator interface,
	 *		otherwise it does not make too much sense.
	 */
	inline bool b_Need_ElementArray_Buffer() const
	{
		return true;
	}

	/**
	 *	@brief gets primitive restart setting
	 *	@return Returns true if primitive restart is enabled, otherwise
	 *		returns false (it is disabled by default).
	 */
	inline bool b_Primitive_Restarts() const
	{
		return m_n_mode == GL_TRIANGLE_STRIP && !m_b_allow_degenerate;
	}

	/**
	 *	@brief gets primitive restart index
	 *	@return Returns primitive restart index (by default 0xffff).
	 */
	inline uint32_t n_Primitive_RestartIndex() const
	{
		return m_n_primitive_restart_index;
	}

	/**
	 *	@brief gets vertex data type
	 *	@return Always returns GL_FLOAT.
	 */
	inline GLenum n_Vertex_DataType() const
	{
		return GL_FLOAT;
	}

	/**
	 *	@brief sets the number of additional vertex elements
	 *	@param[in] n_before_vertex_element_num is number of elements
	 *		to be allocated before each vertex (in GL_FLOATs)
	 */
	inline void Set_Extra_VertexElement_Num(size_t n_before_vertex_element_num)
	{
		_ASSERTE(n_before_vertex_element_num <= INT_MAX);
		m_n_extra_vertex_element_num = int(n_before_vertex_element_num);
	}

	/**
	 *	@brief gets the number of additional vertex elements
	 *	@return Returns number of elements allocated before each vertex (in GL_FLOATs).
	 */
	inline size_t n_Extra_VertexElement_Num() const
	{
		return m_n_extra_vertex_element_num;
	}

	/**
	 *	@brief returns size of the generated vertices
	 *	@return Returns size of the generated vertices, in bytes.
	 */
	inline size_t n_Vertex_Size() const
	{
		return (5 + m_n_extra_vertex_element_num) * sizeof(float);
	}

	/**
	 *	@brief returns OpenGL index data type
	 *	@return Always returns GL_UNSIGNED_INT.
	 */
	inline GLenum n_Index_DataType() const
	{
		return GL_UNSIGNED_INT;
	}

	/**
	 *	@brief counts the number of printable characters in a string
	 *
	 *	@param[in] p_s_utf8 is null-terminated string in utf-8
	 *
	 *	@return Returns number of printable characters in the given string.
	 *
	 *	@note This applies the replacement character policy.
	 *	@note The upper bound may be approximated easily using strlen().
	 *	@note This is intended for output buffer allocation.
	 */
	size_t n_Printable_Char_Num(const char *p_s_utf8) const;

	/**
	 *	@brief counts the number of printable (not space) characters in a string
	 *
	 *	@param[in] p_s_utf8_begin is pointer to the first character of a utf-8 string
	 *	@param[in] p_s_utf8_end is pointer to one past the last character of a utf-8 string
	 *
	 *	@return Returns number of printable characters in the given string.
	 *
	 *	@note This applies the replacement character policy.
	 *	@note The upper bound may be approximated easily using strlen().
	 *	@note This is intended for output buffer allocation.
	 */
	size_t n_Printable_Char_Num(const char *p_s_utf8_begin, const char *p_s_utf8_end) const;

	/**
	 *	@brief gets number of vertices for a given number of printable characters
	 *
	 *	@param[in] n_printable_char_num is number of printable characters
	 *
	 *	@return Returns the number of vertices for the given number of printable characters.
	 *
	 *	@note To get size of the vertices in bytes, multiply by n_Vertex_Size().
	 *	@note To get size of the vertices in elements (GL_FLOATs),
	 *		multiply by n_Vertex_Size() and divide by <tt>sizeof(float)</tt>.
	 */
	inline size_t n_Vertex_Num(size_t n_printable_char_num) const
	{
		return 4 * n_printable_char_num;
	}

	/**
	 *	@brief gets number of indices for a given number of printable characters
	 *	@param[in] n_printable_char_num is number of printable characters
	 *	@return Returns the number of indices for the given number of printable characters.
	 *	@note Depending on the current mode, this is roughly
	 *		5 to 6 indices per displayed character.
	 */
	inline size_t n_Index_Num(size_t n_printable_char_num) const
	{
		return (m_n_mode == GL_TRIANGLES)? n_printable_char_num * 6 :
			n_printable_char_num * 4 + (max(size_t(1), n_printable_char_num) - 1) *
			((m_b_allow_degenerate)? 2 : 1);
	}

	/**
	 *	@brief generates geometry for displayable characters
	 *
	 *	@param[out] p_position is pointer to the array to store the vertex positions
	 *	@param[in] n_position_stride is number of bytes between vertex positions
	 *	@param[out] p_texcoord is pointer to the array to store the vertex texcoords
	 *	@param[out] n_texcoord_stride is number of bytes between vertex texcoords
	 *	@param[in,out] r_n_vertex_space is capacity of the vertex buffer on input (in vertices)
	 *		and the actual number of vertices written upon return
	 *	@param[in] n_index_offset is value of the first vertex index
	 *	@param[out] p_index	is pointer to the array to store indices
	 *	@param[in,out] r_n_index_space is capacity of the index buffer on input (in indices)
	 *		and the actual number of index written upon return
	 *	@param[in] p_s_utf8_begin is the text to be rendered, encoded as utf-8
	 *	@param[in] p_s_utf8_end is pointer to one past the last byte of the text
	 *	@param[in] v_position is position of the first character
	 *	@param[in] f_zoom is relative size of the rendered text
	 *		(if set to 1, the units of generated geometry are pixels)
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note <tt>r_n_vertex_space</tt> is in vertices (ie. each unit is 2 positions + 3 texcoords,
	 *		that is 20 bytes if using 32-bit float for vertices and texcoords).
	 *	@note <tt>r_n_index_space</tt> is in indices (ie. each unit is 4 bytes if using
	 *		uint32_t for indices).
	 *	@note The state, associated with Set_Extra_VertexElement_Num() does not apply
	 *		to this overload of this function.
	 */
	bool Generate_Geometry(float *p_position, int n_position_stride,
		float *p_texcoord, int n_texcoord_stride, size_t &r_n_vertex_space,
		uint32_t n_index_offset, uint32_t *p_index, size_t &r_n_index_space,
		const char *p_s_utf8_begin, const char *p_s_utf8_end,
		Vector2f v_position, float f_zoom) const;

#if 0 // not sure i want to support all these, it is messy

	/**
	 *	@brief generates geometry for displayable characters
	 *
	 *	@param[out] p_position is pointer to the array to store the vertex positions
	 *	@param[in] n_position_stride is number of bytes between vertex positions
	 *	@param[out] p_texcoord is pointer to the array to store the vertex texcoords
	 *	@param[out] n_texcoord_stride is number of bytes between vertex texcoords
	 *	@param[in,out] r_n_vertex_space is capacity of the vertex buffer on input (in vertices)
	 *		and the actual number of vertices written upon return
	 *	@param[in] n_index_offset is value of the first vertex index
	 *	@param[out] p_index	is pointer to the array to store indices
	 *	@param[in,out] r_n_index_space is capacity of the index buffer on input (in indices)
	 *		and the actual number of index written upon return
	 *	@param[in] p_s_utf8 is the text to be rendered, encoded as null-terminated utf-8 string
	 *	@param[in] v_position is position of the first character
	 *	@param[in] f_zoom is relative size of the rendered text
	 *		(if set to 1, the units of generated geometry are pixels)
	 *
	 *	@note r_n_vertex_space is in vertices (ie. each unit is 2 positions + 3 texcoords,
	 *		that is 20 bytes if using 32-bit float for vertices and texcoords).
	 *	@note r_n_index_space is in indices (ie. each unit is 4 bytes if using
	 *		uint32_t for indices).
	 */
	inline bool Generate_Geometry(float *p_position, int n_position_stride,
		float *p_texcoord, int n_texcoord_stride, size_t &r_n_vertex_space,
		uint32_t n_index_offset, uint32_t *p_index, size_t &r_n_index_space,
		const char *p_s_utf8, Vector2f v_position, float f_zoom) const
	{
		return Generate_Geometry(p_position, n_position_stride, p_texcoord,
			n_texcoord_stride, r_n_vertex_space, n_index_offset, p_index,
			r_n_index_space, p_s_utf8, (p_s_utf8)? p_s_utf8 + strlen(p_s_utf8) : 0,
			v_position, f_zoom);
		// handle null-terminated
	}

	/**
	 *	@brief generates geometry for displayable characters (a simpler variant where the
	 *		vertices are assumed to be in interleaved 3D texcoord, 2D position format)
	 *
	 *	@param[out] p_t3v2_vertex is pointer to the array to store the vertex data
	 *	@param[in,out] r_n_vertex_space is capacity of the vertex buffer on input (in vertices)
	 *		and the actual number of vertices written upon return
	 *	@param[in] n_index_offset is value of the first vertex index
	 *	@param[out] p_index	is pointer to the array to store indices
	 *	@param[in,out] r_n_index_space is capacity of the index buffer on input (in indices)
	 *		and the actual number of index written upon return
	 *	@param[in] p_s_utf8_begin is the text to be rendered, encoded as utf-8
	 *	@param[in] p_s_utf8_end is pointer to one past the last byte of the text
	 *	@param[in] v_position is position of the first character
	 *	@param[in] f_zoom is relative size of the rendered text
	 *		(if set to 1, the units of generated geometry are pixels)
	 *
	 *	@note r_n_vertex_space is in vertices (ie. each unit is 2 positions + 3 texcoords,
	 *		that is 20 bytes if using 32-bit float for vertices and texcoords).
	 *	@note r_n_index_space is in indices (ie. each unit is 4 bytes if using
	 *		uint32_t for indices).
	 */
	inline bool Generate_Geometry(float *p_t3v2_vertex, size_t &r_n_vertex_space,
		uint32_t n_index_offset, uint32_t *p_index, size_t &r_n_index_space,
		const char *p_s_utf8_begin, const char *p_s_utf8_end,
		Vector2f v_position, float f_zoom) const
	{
		return Generate_Geometry(p_t3v2_vertex + 3, 5 * sizeof(float), p_t3v2_vertex,
			5 * sizeof(float), r_n_vertex_space, n_index_offset, p_index,
			r_n_index_space, p_s_utf8_begin, p_s_utf8_end, v_position, f_zoom);
	}

	/**
	 *	@brief generates geometry for displayable characters (a simpler variant where the
	 *		vertices are assumed to be in interleaved 3D texcoord, 2D position format)
	 *
	 *	@param[out] p_t3v2_vertex is pointer to the array to store the vertex data
	 *	@param[in,out] r_n_vertex_space is capacity of the vertex buffer on input (in vertices)
	 *		and the actual number of vertices written upon return
	 *	@param[in] n_index_offset is value of the first vertex index
	 *	@param[out] p_index	is pointer to the array to store indices
	 *	@param[in,out] r_n_index_space is capacity of the index buffer on input (in indices)
	 *		and the actual number of index written upon return
	 *	@param[in] p_s_utf8 is the text to be rendered, encoded as null-terminated utf-8 string
	 *	@param[in] v_position is position of the first character
	 *	@param[in] f_zoom is relative size of the rendered text
	 *		(if set to 1, the units of generated geometry are pixels)
	 *
	 *	@note r_n_vertex_space is in vertices (ie. each unit is 2 positions + 3 texcoords,
	 *		that is 20 bytes if using 32-bit float for vertices and texcoords).
	 *	@note r_n_index_space is in indices (ie. each unit is 4 bytes if using
	 *		uint32_t for indices).
	 */
	inline bool Generate_Geometry(float *p_t3v2_vertex, size_t &r_n_vertex_space,
		uint32_t n_index_offset, uint32_t *p_index, size_t &r_n_index_space,
		const char *p_s_utf8, Vector2f v_position, float f_zoom) const
	{
		return Generate_Geometry(p_t3v2_vertex + 3, 5 * sizeof(float), p_t3v2_vertex,
			5 * sizeof(float), r_n_vertex_space, n_index_offset, p_index, r_n_index_space,
			p_s_utf8, v_position, f_zoom);
	}

#endif // 0

	/**
	 *	@brief generates geometry for displayable characters
	 *
	 *	This can be used to render a mixture of strings with different positioning, size
	 *	or color.
	 *
	 *	By default, this only generates texture coordinates and vertex positions (in this
	 *	order). Use Set_Extra_VertexElement_Num() to add colors or other per-vertex
	 *	information. The values of the extra elements are undefined and need to be filled
	 *	by the caller.
	 *
	 *	To render strings with discontinuous positioning (such as text with explicit
	 *	paragraph alignment), this can be called multiple times with individual text
	 *	segments and explicit positions. The geometry automatically accumulates in the
	 *	buffers. In each call, set <tt>n_index_offset</tt> to the number of vertices,
	 *	accumulated so far.
	 *
	 *	@param[out] r_t3v2_vertex_list is vertex list (new vertices appended on success;
	 *		3D texcoord comes first, then 2D position)
	 *	@param[in] n_index_offset is value of the first vertex index
	 *	@param[out] r_index_list is vertex index list (new indices appended on success)
	 *	@param[in] p_s_utf8_begin is the text to be rendered, encoded as utf-8
	 *	@param[in] p_s_utf8_end is pointer to one past the last byte of the text
	 *	@param[in] v_position is position of the first character
	 *	@param[in] f_zoom is relative size of the rendered text
	 *		(if set to 1, the units of generated geometry are pixels)
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note The geometry is appended, not replaced.
	 *	@note To get correct results, all the geometry must be generated
	 *		using the same mode and vertex size.
	 *	@note The texture coordinates are 3D even in 2D mode.
	 */
	bool Generate_Geometry(std::vector<float> &r_t3v2_vertex_list, uint32_t n_index_offset,
		std::vector<uint32_t> &r_index_list, const char *p_s_utf8_begin,
		const char *p_s_utf8_end, Vector2f v_position, float f_zoom) const;

	/**
	 *	@brief generates geometry for displayable characters
	 *
	 *	This can be used to render a mixture of strings with different positioning, size
	 *	or color.
	 *
	 *	By default, this only generates texture coordinates and vertex positions (in this
	 *	order). Use Set_Extra_VertexElement_Num() to add colors or other per-vertex
	 *	information. The values of the extra elements are undefined and need to be filled
	 *	by the caller.
	 *
	 *	To render strings with discontinuous positioning (such as text with explicit
	 *	paragraph alignment), this can be called multiple times with individual text
	 *	segments and explicit positions. The geometry automatically accumulates in the
	 *	buffers. In each call, set <tt>n_index_offset</tt> to the number of vertices,
	 *	accumulated so far.
	 *
	 *	@param[out] r_t3v2_vertex_list is vertex list (new vertices appended on success;
	 *		3D texcoord comes first, then 2D position)
	 *	@param[in] n_index_offset is value of the first vertex index
	 *	@param[out] r_index_list is vertex index list (new indices appended on success)
	 *	@param[in] p_s_utf8 is null-terminated string, containing the text to be
	 *		rendered, encoded as utf-8
	 *	@param[in] v_position is position of the first character
	 *	@param[in] f_zoom is relative size of the rendered text
	 *		(if set to 1, the units of generated geometry are pixels)
	 *
	 *	@return Returns true on success, false on failure.
	 *
	 *	@note The geometry is appended, not replaced.
	 *	@note To get correct results, all the geometry must be generated
	 *		using the same mode and vertex size.
	 *	@note The texture coordinates are 3D even in 2D mode.
	 */
	inline bool Generate_Geometry(std::vector<float> &r_t3v2_vertex_list,
		uint32_t n_index_offset, std::vector<uint32_t> &r_index_list,
		const char *p_s_utf8, Vector2f v_position, float f_zoom) const
	{
		return Generate_Geometry(r_t3v2_vertex_list, n_index_offset,
			r_index_list, p_s_utf8, (p_s_utf8)? p_s_utf8 +
			strlen(p_s_utf8) : 0, v_position, f_zoom);
	}

	/**
	 *	@brief calculates size of a block of text
	 *
	 *	@param[in] p_s_utf8 is the text to be rendered, encoded as null-terminated utf-8 string
	 *	@param[in] f_zoom is relative size of the rendered text
	 *		(if set to 1, the units of generated geometry are pixels)
	 *
	 *	@return Returns size of the text as a Vector3f, where (x, y) contain the
	 *		final caret shift, z contains width of the text in the widest point.
	 */
	inline Vector3f v_Text_Size(const char *p_s_utf8, float f_zoom) const
	{
		return v_Text_Size(p_s_utf8, (p_s_utf8)? p_s_utf8 +
			strlen(p_s_utf8) : 0, f_zoom);
	}

	/**
	 *	@brief calculates size of a block of text
	 *
	 *	@param[in] p_s_utf8_begin is the text to be rendered, encoded as utf-8
	 *	@param[in] p_s_utf8_end is pointer to one past the last byte of the text
	 *	@param[in] f_zoom is relative size of the rendered text
	 *		(if set to 1, the units of generated geometry are pixels)
	 *
	 *	@return Returns size of the text as a Vector3f, where (x, y) contain the
	 *		final caret shift, z contains width of the text in the widest point.
	 */
	Vector3f v_Text_Size(const char *p_s_utf8_begin,
		const char *p_s_utf8_end, float f_zoom) const;

protected:
	static inline bool b_Is_Glyph(int n_code);

private:
	CGLBitmapFont2(const CGLBitmapFont2 &r_other); // no-copy
	CGLBitmapFont2 &operator =(const CGLBitmapFont2 &r_other); // no-copy
};

#endif // !__BITMAP_FONT2_INCLUDED
