Let Ogre support Chinese (2)
---- Support TTF font
0. Or preface
If you want to understand this article, please make sure you have seen the "Let Ogre support Chinese", because this article is written on the basis of the previous article, and assume that the document has been in accordance with the previous article. surgery. But if you just want to use the TTF font, just download the files included in this article, you can recompile.
Review
As mentioned above, we have implemented a bitmap font. But when you think about it, you can find many of the defects. Reading a 548 * 2048 bitmap, equal to saving a 2048 * 2048 map in the memory, do not say that all graphics cards support such a big map, single is the appetite of each Font font class, it is enough to be Heart shot. If you define enough font classes, I think your game configuration requirement, in some ways to exceed "doom3".
And this is not the only defect, the text size is too much relative to the bitmap size, causing the text position error of the floating point number, you can see the shadow of other words next to a text. (Although it can be solved by increasing the word spacing.) There is also a defect of a dotted font itself, which is a single shape, not suitable for zooming in narrowing, some text edges, enough to extinguish any player's input.
It seems that TTF is the only solution.
2. basic knowledge
(1) TTF font.
TTF is a vector font. We often hear the vector, like the vector graphics in Flash, Flash made at 100 * 100 resolution, even if it enlarges to full screen, the displayed screen does not appear mosaic. The so-called vector, in fact, it is to describe graphics with points and lines, so that when the graph needs to be enlarged, just enlarge the corresponding multiples of all this graphic and lines. Moreover, there are many TTF fonts on the website to download, or you can go to buy some special fonts. Then when you release the game you carefully make, you can use these suffixes for .ttf files. Including the shocking of Quake, is also the TTF font library.
(2) Freetype2 library
In http://www.freetype.org, there is a free library of FreeType, and it is OpenSource. It currently has 2 versions: 1.0 and 2.0. The difference is that 1.0 can only read the TTF format, and 2.0 supports more file formats, please read the License to follow before using it. The following is a list of support from Freetype 2.0 to the font library:
TrueType Fonts (and Collectes)
Type 1 FONTS
Cid-Keyed Type 1 FONTS
CFF FONTS
OpenTYPE FONTS (Both TrueType and CFF Variants)
SFNT-BASED BITMAP FONTS
X11 PCF FONTS
Windows FNT FONTS
(3) "Main Ideology"
Please refer to the article "Implementation and Skills of Chinese Characters" in the Yanlong Studio, but unfortunately use the Windows API, the author is a thousand miles liver, search online.
Incidentally, the above two are cut directly from this article,> _ 3. Surgery --- troublesome than you think (1) First of all, tell the font class, what words we need next to our next rendering. Instead, the font class can release the unused font when needed. In the font class ~ a. Add data bool musing [ogre_num_glyphs]; used to mark text is used. b. Increase functions Inline void setusing (std :: vector { MEMSET (this-> musing, 0, sizeof (this-> musing)); Std :: Vector For (it = caption.begin (); it! = caption.end (); IT) { IF (OGRE_GLYPH_INDEX (* IT) this-> MUSING [ogre_glyph_index (* it)] = 1; // Tag text is used } } And call this function in Void TextareAguielement :: UpdateGeometry (). (2) Then modify the void font :: CreateTextureFromFont (Void); The Font class is on a 2 ^ n * 2 ^ N profile through the void font :: createtetexturefromfont (void), and then save the English word. We need to modify: a. Separate and save the freetyPE2 and the auxiliary variables from the word. We save and process these variables through a class. Class TTFMSG { Class max // class, used to save a few "biggest", { INT Nothing; // This is used to place it, it is meaningless. Anyway, no, but if he is running, it may be related to the data. PUBLIC: INT Height; // Text Maximum Height Int width; // maximum width INT BEAR; / / Maximum Void? } PUBLIC: FT_Library FTLIBRARY; / / FREETYPE2 FT_FACE FACE; / / FREETYPE2 interface? uint char_spacer; // text void SDDATACHUNK TTFCHUNK; // Data block, used to save TTF information Ft_f26dot6 ftsize; // freetype2 font size Std :: pair SDDATAUNK IMGCHUNK; // Data block, used to save bitmap information Bool dirty; // mark, see if you need to update the map Max max; // Several largest Inline Bool INIT / / This is the initialization function in Void Font :: CreateTextureFromFont (Void); medium transfer. { // The following is initialization, most of them are from void font :: createtextureFromFont (void); transplanted Dirty = false; IF (ft_init_freeetype (& fTlibrary)) Except (Exception :: Err_internal_ERROR, "Could Not Init Freetype Library!", "Font :: font"); CHAR_SPACER = 5; FONTMANAGER :: getsingleton () ._ FindResourceData (font-> msource, ttfchunk); IF (ft_new_memory_face (ftlibrary, ttfchunk.getptr (), (ft_long) TTFCHUNK.GETSIZE (), 0, & face) Except (Exception :: Err_internal_ERROR, "Could NOT OPEN FONT FACE!", "Font :: createtexturefromfont"); FTSIZE = (ft_f26dot6) (font-> mttfsize * (1 << 6)); IF (ft_set_char_size (face, ftsize, 0, font-> mttfreesolution, 0)) Except (Exception :: Err_internal_error, "Could Not Set Char Size!", "Font :: CreateTextureFromFont"); Return True; } Inline bool done () { / / Call in the font deconstruction function, I should call the following two functions, but I don't know why one call is wrong, it is not necessary. // ft_done_face (face); // ft_done_freeetype (ftlibrary); Return True; } Inline Bool getRect (Image :: Rect & Rect) // This function is used later, it is a empty position for finding a map { IF (511 { Rect.right = Rect.top = Rect.Left = Rect.bottom = -1; Return False; } IF (511 { Point.second = max.width char_spacer; Point.first = 0; IF (511 { Rect.right = Rect.top = Rect.Left = Rect.bottom = -1; Return False; } } Rect.left = Point.first; Rect.top = Point.second; Rect.bottom = max.height; Rect.right = max.width; Point.first = max.width char_spacer; Return True; } } The above class definition In the Font class, add TTFMSG * MTTFMSG data in Font, and mttfmsg = new TTFMSG in the constructor; It is modifying void font :: creteTextureFromFont (void); function, mainly, first is to separate a lot of variables and constructive into the TTFMSG class, then the map from 2 ^ n * 2 ^ n to fixed 512 * 512 Why do you want this number because 256 is too small (nonsense). It can guarantee that the text area of 512 * 512 does not appear in a case where it is not a picture (all English symbols no repetitive Chinese characters), this safety area is basically enough. (What, you have to draw a screen of the Chinese characters? Then you look at the change.) There is also an important function to find 100 Chinese characters, find the highest and wide and maximum gaps. Modify this look ~ Void font :: CreateTextureFromFont (void) { MTTFMSG-> INIT (THIS); // Initialization FreeType2uint I, L, M, N; INT J, K; FILE * fo_def = stdout; // 啥意? I don't understand INT max_height = 0, max_width = 0, MAX_BEAR = 0; uint startglyph = 33; uint endglyph = 167; // Find in English to find the highest and broader and maximum gap // Calculate Maximum Width, Height and Bearing For (i = startglyph, l = 0, m = 0, n = 0; i { Ft_load_char (Mttfmsg-> Face, I, Ft_Load_render); // The << 6 and >> 6 is all the data in freetype2 and the conversion of our data we use. IF ((2 * (mttfmsg-> face-> glyph-> bitmap.rows << 6) - mttfmsg-> face-> glyph-> metrics.horibearingy)> max_height) Max_height = (2 * (mttfmsg-> face-> glyph-> bitmap.rows << 6) - mttfmsg-> face-> glyph-> metrics.horibearingy); IF (mttfmsg-> face-> glyph-> metrics.horibearingy> max_bear) Max_bear = mttfmsg-> face-> glyph-> metrics.horibearing; IF ((mttfmsg-> face-> glyph-> advance.x >> 6) (mttfmsg-> face-> glyph-> metrics.horibearingx >> 6)> max_width) Max_width = (mttfmsg-> face-> glyph-> advance.x >> 6) (mttfmsg-> face-> glyph-> metrics.horibearingX >> 6); } // The following for is looking for 100 Chinese characters, finds the highest and widest and maximum gaps for reference. Aunt, the most Chinese characters are in this 100. For (i = 20643, l = 0, m = 0, n = 0; i <20743; i ) { Ft_load_char (Mttfmsg-> Face, I, Ft_Load_render); IF ((2 * (mttfmsg-> face-> glyph-> bitmap.rows << 6) - mttfmsg-> face-> glyph-> metrics.horibearingy)> max_height) Max_height = (2 * (mttfmsg-> face-> glyph-> bitmap.rows << 6) - mttfmsg-> face-> glyph-> metrics.horibearingy); IF (mttfmsg-> face-> glyph-> metrics.horibearingy> max_bear) max_bear = mttfmsg-> face-> glyph-> metrics.horibearing; IF ((mttfmsg-> face-> glyph-> advance.x >> 6) (mttfmsg-> face-> glyph-> metrics.horibearingx >> 6)> max_width) Max_width = (mttfmsg-> face-> glyph-> advance.x >> 6) (mttfmsg-> face-> glyph-> metrics.horibearingX >> 6); IF ((mttfmsg-> face-> glyph-> advance.x) (mttfmsg-> face-> glyph-> metrics.horibearingx)> mttfmsg-> max.width) MTTFMSG-> max.width = (mttfmsg-> face-> glyph-> advance.x) (mttfmsg-> face-> glyph-> metrics.horibearingx); } // The following lines don't need we need 512 * 512 Size_t tex_side = 512; // is this 512 // Define the data width because it is a 32-bit bitmap four char than a pixel, why can't I use 8? I try to change, but I will not be transparent. I hope that the master can see if I can change. SIZE_T DATA_WIDTH = TEX_SIDE * 4; LogManager :: getsingleton (). LogMessage ("font" mname "using texture size" Stringconverter :: TOSTRING (TEX_SIDE) "X" StringConverter :: toString (tex_side)); Uchar * imageData = new uchar [tex_side * tex_side * 4]; // Set a space for saving the bitmap // Reset Content MEMSET (imagedata, 0, tex_side * tex_side * 4); // Clear For (i = startglyph, l = 0, m = 0, n = 0; I { FT_ERROR FTRESULT; // load & render Glyph FTRESULT = ft_load_char (mttfmsg-> face, i, ft_load_render); // Read the font IF (fTRESULT) { // problem loading this glyph, continue Logmanager :: getsingleton (). LogMessage ("Info: Cannot Load Character" StringConverter :: TSTRING (i) "in font" mname); Continue; // If the error is skipped } / / Should be a width ft_int advance = (mttfmsg-> face-> glyph-> advance.x >> 6) (mttfmsg-> face-> glyph-> metrics.horibearingX >> 6); // Get a bitmap of Freetype2 Unsigned char * buffer = mttfmsg-> face-> glyph-> bitmap.buffer; IF (! buffer) { // Yuck, ft Didn't Detect this But generated a null pointer! LogManager :: getsingleton (). LogMessage ("Info: FreeType Returned Null for Character" StringConverter :: TSTRING (i) "in font" mname); Continue; // If you don't get skipping } // Get Y's gap (maximum empty - empty - this word empty) is to say that the bottom of these words is flat. INT Y_Bearnig = (Max_Bear >> 6) - (mttfmsg-> face-> glyph-> metrics.horibearing >> 6); For (j = 0; j { INT ROW = J M Y_Bearnig; // Relative row this word in the bitmap gap INT COL = L; // Column Uchar * pdest = & imagedata [(rot * data_width) l * 4]; // Found For (k = 0; k { IF (mantialiascolour) // understands, is it a gray font? { // Use the Same Greyscale Pixel for All Components RGBA * PDEST = * buffer; * PDEST = * buffer; * PDEST = * buffer; } Else { // Clamp Color to Full White or Off IF (* buffer> 0) { * PDEST = 0xff; * PDEST = 0xff; * PDEST = 0xff; } Else { * PDEST = 0; * PDEST = 0; * PDEST = 0; } } // ALWAYS Use The Greyscale Value for Alpha * PDEST = * buffer ; // alpha! I don't know why I don't know why? } } this-> setglyphtexcoords (i, (REAL) L / (REAL) TEX_SIDE, // U1 (REAL) M / (REAL) TEX_SIDE, // V1 (REAL) (L (MTTFMSG-> Face-> Glyph-> Advance.x >> 6)) / (real) TEX_SIDE, // U2 (REAL) (M (MAX_HEIGHT >> 6) / (REAL) TEX_SIDE / / V2 ); // Set the coordinates // advance a column L = (Advance MTTFMSG-> Char_Spacer); // L = this word wide word empty // if at end of row // If the head is not a word IF (Tex_SIDE - 1 { M = (Max_Height >> 6) MTTFMSG-> char_spacer; L = n = 0; } } // Save the information to our MTTFMSG> _ < IF (l) MTTFMSG-> Point.second = m (max_height >> 6) mttfmsg-> char_spacer; Else MTTFMSG-> Point.second = m; MTTFMSG-> Point.First = 0; // // The following is to save a few biggest. MTTFMSG-> max.height = max_height >> 6; MTTFMSG-> max.bear = max_bear >> 6; MTTFMSG-> max.width = max_width; MTTFMSG-> imgchunk.allocate (tex_side * tex_side * 4, imagedata); / / I don't know why IMG this intermediate variable seems to be created directly from Chunk. // - image img; //img.loadrawdata (imgchunk, tex_side, tex_side, pf_a8r8g8b8); // 贴 图 名 String texname = mname "texTure"; // load texture with no mipmaps // Create a bitmap from the img to create a map from Chunk // TextureManager :: getsingleton (). LoadingImage (TexName, IMG, TEX_TYPE_2D, 0); TextureManager :: getsingleton () (). LoadrawData (TexName, Mttfmsg-> Imgchunk, Tex_SIDE, TEX_SIDE, PF_A8R8G8B8, TEX_TYPE_2D, 0); TEXTUREUNITSTATE * T = mpmaterial-> getTechnique (0) -> getpass (0) -> CreateTextureUnitState (TexName); // Allow Min / Mag Filter, But no MIP T-> settexturefiltering (fo_linear, fo_Linear, fo_none); // SDDATACHUNK WILL DELETE ImageData } You should have a lot of prior to the previous function. (3) Then the most important thing is a dynamic application and picture. First of all, the most important thing is that we want a way to get the unicode code of Chinese characters. We use the UnicodeMap array, provide a location code to Unicode's conversion work, wait for this form to give you, it is hard to find it from the Internet, unfortunately this The table does not correspond to the correspondence of the Chinese punctuation, and if you want to support Chinese punctuation, you must work hard to find the Unicode code and add this table. This table is such a Char C [3] = ""; UnicodeMap [94 * (C [0] -0xa0-1) C [1] -0xa0-1]; you get the Unicode code, don't know why Is there a Unicode code from 5165 ~ 5169, is it a wheel? Apply for rendering (word) { IF (with this word) Return position Else { IF (with space) Graphics Else I can't find the word // can't find it, no place to draw. Delete this location Return position } } It is very intuitive, generally, this means, the application rendering is the inline void getglyphtexcoords (Unsigned Long ID, Real & U1, Real & V1, Real & U2, REAL & V2) Const. Remove the const change. get a. Application Rendering Inline void getGlyphtexco Coords (unsigned long ID, Real & U1, Real & V1, Real & U2, REAL & V2) { Unsigned long idx = ogre_glyph_index (id); IF (this-> mtype == ft_trueType) // TTF? IF (id> = 161 && idx IF (! mTEXCOORDS_V2 [IdX]) / / Isn't? setchar (id); // U1 = mtExcoords_u1 [idx]; V1 = mtExcoords_v1 [idx]; U2 = mtExcoords_u2 [idx]; V2 = mtExcoords_v2 [idx]; } b. Picture, etc. Bool font :: setchar (unsigned long dwchar) { INT J, K; Uchar * pdest; // Pointer to operate data MProportion = 0.8; // I don't know why, I always feel that Chinese is too flat, so set this parameter, the parameters created in "Let Ogre support Chinese". Image :: Rect Rect; // Position of the word IF (! mttfmsg-> getRect (Rect) / * look back at this function * /) // If you don't get a space location { For (int i = 161; i { IF (! MUSING [I] && mTexCoRDS_V2 [i]) { // Get coordinates Rect.Left = mTexcoRDS_U1 [I] * 512; RECT.TOP = mTEXCOORDS_V1 [I] * 512; Rect.bottom = MTTFMSG-> max.height; Rect.right = mttfmsg-> max.width; // Erase (this code has not been tested, etc. After the input class is checked) For (j = 0; j { PDEST = MTTFMSG-> imgchunk.getptr (); PDEST = ((J Rect.top) * (512 * 4)) Rect.Left * 4; MEMSET (PDEST, 0, MTTFMSG-> max.width * 4); } MTEXCOORDS_U1 [I] = mTEXCOORDS_V1 [i] = mtExcoords_u2 [i] = mTexCoRDS_V2 [i] = 0; Break; } } IF (Rect.top == - 1) // Ah, ah, ah, ah, the map is actually used, no way, wrong { Logmanager :: getsingleton (). LogMessage ("You are too greedy, the Chinese characters used are too much, this is the punishment for you."); Return False; } } // The following pictures are all hugged, File * fo_def = stdout; FT_ERROR FTRESULT; // load & render Glyph FTRESULT = ft_load_char (mttfmsg-> face, unicodemap [dwchar-161], ft_load_render); // read font IF (fTRESULT) { // problem loading this glyph, continue Logmanager :: getsingleton (). LogMessage ("Info: Cannot Load Character" StringConverter :: TOSTRING (UnicodeMap [DWCHAR-161]) "in font" mname); Return false; // If the error is skipped } Unsigned char * buffer = mttfmsg-> face-> glyph-> bitmap.buffer; // bit map pointer IF (! buffer) { // Yuck, ft Didn't Detect this But generated a null pointer! LogManager :: getsingleton (). LogMessage ("Info: 1111Freetype Returned Null for Character" StringConverter :: TOSTRING (UnicodeMap [DWCHAR-161]) "in font" mname); Return false; // If you don't get skipping } Int y_bearnig = (mttfmsg-> max.bear) - (mttfmsg-> face-> glyph-> metrics.horibearingy >> 6); For (j = 0; j { INT row = j Rect.top y_Bearnig; INT col = Rect.Left; // PDEST = MTTFMSG-> imgchunk.getptr (); PDEST = (row * (512 * 4)) col * 4; For (k = 0; k { IF (MantialiaScolour) { // Use the Same Greyscale Pixel for All Components RGBA * PDEST = * buffer; * pdest = * buffer; * PDEST = * buffer; } Else { // Clamp Color to Full White or Off IF (* buffer> 0) { * PDEST = 0xff; * PDEST = 0xff; * PDEST = 0xff; } Else { * PDEST = 0; * PDEST = 0; * PDEST = 0; } } // ALWAYS Use The Greyscale Value for Alpha // logmanager :: getsingleton (). LogMessage (Stringconverter :: Tostring (* buffer) "is cool"); * PDEST = * buffer ; } } // Set location This-> setglyphtexcoords (dwchar, (Real) Rect.Left / 512.0f, // u1 (REAL) RECT.TOP / 512.0F, // V1 (Real) (Rect.Left (MTTFMSG-> Face-> Glyph-> Advance.x >> 6)) / 512.0F, // U2 (Rect.top Rect.Bottom) / 512.0F // v2 ); MTTFMSG-> dirty = true; // map needs to be updated Return True; } (4) Think of the pine, heavy work is done, it is updated. Font class ~ Inline void write () { IF (MTTFMSG-> DIRTY) { // Replace the map, by the way, the function of the similar function is also // Virtual Void Blittotexture (const image & src, unsigned ustartx, unsigned ustarty) = 0 // and Virtual Void BlitImage (Const Image & src, Const Image :: Rect TexRect) / / But blittotexture () is not implemented until OGRE-Win32-V0-14-0 has not been used. BlitImage () does not have it now. TextureManager :: getsingleton (). Unload (mname "texture"); TextureManager :: getsingleton (). LoadrawData (MNAME "Texture", MTTFMSG-> IMGCHUNK, 512, 512, PF_A8R8G8B8, TEX_TYPE_2D, 0); MTTFMSG-> dirty = false; } } This function is called in the void textareaguielement :: updateGeometry (). 4. result. Good long, wrote a long. Although mostly the code, it is also very tired to write a comment. Relive the results of these days. Just like the previous one "successfully supported Chinese in OpenGL and DX9.0, but DX7.0 actually had an operation error, and the specific problem is not clear, but also high-end advice." However, I didn't support DX7, no matter what it was. The rendering of OpenGL is clear than DX9.0 is the reason for my graphics card? The above WinXP VS2003.NET El Sha 980SE is passed ~. . By the way, the last time I published it, I didn't expect many friends and the high people to find me. I even contacted a South of the company, saying that I have to do an engine support Chinese. But after the sold 400 train tickets, it actually because the housing problem was invalidated, 5555, the refund was 80 yuan. Or yourself, if you can learn more, you may have to put ~. Work hard, strive to write "Let Ogre support Chinese" three songs. The next article should be "can enter Chinese". It may not be written ~~~~~~~~~~~~~~~~~~~~ Related documents Chinese.fontdef // font information files are placed in resource files Font.png // Font Image in resource file plus Ogrefont.cpp Ogrefont.h OgrefontManager.cpp OgretextAreaguielement.cpp // The above file overrides the same name file to back up Solo5.ttf // This is a Chinese TTF I have replaced the original TTF directly. UnicodeMap.h // This is an important, which is the array of Unicode codes (mentioned in the article) This is changed on the OGRE-Win32-V0-14-0 basis (the last OGRE-Win32-V0-13-1), Please go to http://sourceforge.net/projects/ogre/ download Film Download: http://www.gameres.com/articles/program/visual/3d/ogre/ttf.files/file.rar Free wager QQ: 1850070 From: Gameres http://www.gameres.com In the above figure, "Free Works TTF: 213.786" is TTF. Others are bitmap, the Chinese bitmap font also modified, supporting the half-way font ~