Example #1
0
        // ###############################################################################
        // ### C O N S T R U C T I O N   A N D   I N I T I A L I Z A T I O N
        // ###############################################################################

        #region Construction

        /// <summary>Initialize a new instance of the <see cref="FreeType.Font3D"/> class with font and size.</summary>
        /// <param name="font">The font file path.</param>
        /// <param name="size">The requested font size.</param>
        public FtFont(string font, int size)
        {
            if (sizeof(FtLong) != IntPtr.Size)
            {
                Console.WriteLine("Wrong compilation options!");
                if (IntPtr.Size == 4)
                {
                    Console.WriteLine("Do not use 'X11_64' on 32 bit OS!");
                }
                else
                {
                    Console.WriteLine("Use 'X11_64' on 64 bit OS!");
                }

                return;
            }

            // Save the size we need it later on when printing
            _fontSize = size;

            // We begin by creating a library pointer
            int ret = FtLibrary.FT_Init_FreeType(out IntPtr libptr);

            if (ret != 0)
            {
                return;
            }

            //Once we have the library we create and load the font face
            int retb = FtFace.FT_New_Face(libptr, font, 0, out IntPtr faceptr);

            if (retb != 0)
            {
                return;
            }

            var face = (FtFace)Marshal.PtrToStructure(faceptr, typeof(FtFace));

            if ((((int)face.face_flags) & ((int)((FtLong)FtFaceFlags.FtFaceFlagHorizontal))) !=
                (int)((FtLong)FtFaceFlags.FtFaceFlagHorizontal))
            {
                Console.WriteLine("WARNING! The font '" + font + "' is not suitable for horizontal left-to-right text output.");
            }

            if ((((int)face.face_flags) & ((int)((FtLong)FtFaceFlags.FtFaceFlagFixedWidth))) !=
                (int)((FtLong)FtFaceFlags.FtFaceFlagFixedWidth))
            {
                _monospace = false;
            }
            else
            {
                _monospace = true;
            }
            uint tmp = (((('u' << 8) | 'n') << 8 | 'i') << 8 | 'c');

            if (FtFace.FT_Select_CharMap(faceptr, tmp) != 0)
            {
                throw new Exception("Cannot set unicode");
            }

            // Freetype measures the font size in 1/64th of pixels for accuracy
            // so we need to request characters in size*64
            FtFace.FT_Set_Char_Size(faceptr, size << 6, size << 6, 96, 96);

            // Provide a reasonably accurate estimate for expected pixel sizes
            // when we later on create the bitmaps for the font.
            FtFace.FT_Set_Pixel_Sizes(faceptr, size, size);



            FtSize ftSize = Marshal.PtrToStructure <FtSize>(face.size);

            _baseLine = ((int)ftSize.metrics.ascender + (int)ftSize.metrics.descender) / 64;// (int)ft_size.metrics.ascender/64;


            // Once we have the face loaded and sized, we generate opengl textures
            // from the glyphs for each printable character.
            _textures = new int[CharacterRange];
            _extentsX = new int[CharacterRange];
            _listBase = GL.GenLists(CharacterRange);
            GL.GenTextures(CharacterRange, _textures);
            Console.WriteLine($"{font} {size}");
            for (int c = 0; c < CharacterRange; c++)
            {
                CompileCharacter(face, faceptr, c);
            }

            // Dispose of these as we don't need
            FtFace.FT_Done_Face(faceptr);
            FtLibrary.FT_Done_FreeType(libptr);
        }
Example #2
0
        // ###############################################################################
        // ### M E T H O D S
        // ###############################################################################

        #region Methods

        /// <summary>Compile a single character to a list of GL commands, that draw the character's glyph bitmap.</summary>
        /// <param name="face">The font face, associated with the character to compile.</param>
        /// <param name="faceptr">The font face pointer, associated with the character to compile.</param>
        /// <param name="c">The character to compile to a list of GL commands, that draw the character's glyph bitmap.</param>
        /// <remarks>For details see: http://www.freetype.org/freetype2/docs/tutorial/step2.html</remarks>
        public void CompileCharacter(FtFace face, IntPtr faceptr, int c)
        {
            int result;
            // Convert the number index to a character index.
            int index = FtFace.FT_Get_Char_Index(faceptr, Convert.ToChar(c));

            // Load a single glyph (indicated by the index of the glyph in the font file) into the glyph slot of a face object.
            // The FT_LOAD_TYPES.FT_LOAD_DEFAULT controls:
            // - PRINARILY: Look for a bitmap of the glyph, corresponding to the face's current size (if the glyph of the current size
            //              has already been loaded and provided as bitmap), provide bitmap data to the glyph slot and return integer 0.
            // - ALTERNATIVELY: Look for a scalable outline, load it from the font file, scale it to device pixels, ‘hint’ it to the
            //                  pixel grid (in order to optimize it), provide outline data to the glyph slot and return integer 0.
            // - FALLBACK: Return integer != 0.
            result = FtFace.FT_Load_Glyph(faceptr, index, /*get metrics in 1/64th of pixels*/ FtLoadTypes.FtLoadDefault);
            if (result != 0)
            {
                return;
            }

            // Extract a glyph from the glyph slot. The 'face' is a managed mirror of the 'faceptr' and therefore it shares the pointer.
            // The FT_Load_Glyph() has already provided the glyph to 'faceptr.glyphrec', that can also be accessed via 'face.glyphrec'.
            // The created glyph object must be released with FT_Done_Glyph().
            result = Glyph.FT_Get_Glyph(face.glyphrec, out IntPtr glyphPointer);
            if (result != 0)
            {
                return;
            }

            // Convert a given glyph object to a bitmap glyph object.
            // The bitmap glyph object must be released with FT_Done_Glyph().
            result = Glyph.FT_Glyph_To_Bitmap(out glyphPointer,
                                              /*8-bit anti-aliased pixmap*/ FtRenderModes.FtRenderModeNormal,
                                              /*origin*/ new FtVector(0, 0),
                                              /*destroy non-bitmap glyph before replacing*/ (FtBool)1);
            if (result != 0)
            {
                return;
            }

            // Incorporate glyph bitmap structure into managed code.
            FtBitmapGlyph bitmapglyphStructure = (FtBitmapGlyph)Marshal.PtrToStructure(glyphPointer, typeof(FtBitmapGlyph));
            uint          size = (bitmapglyphStructure.bitmap.width * bitmapglyphStructure.bitmap.rows);

            if (size <= 0)
            {
                _extentsX[c] = 0;
                // Space is a special `blank` character, that must be supported by a glyph bitmap.
                if (c == 32)
                {
                    GL.NewList((uint)(_listBase + c), ListMode.Compile);
                    GL.Translate(_fontSize >> 2, 0, 0);
                    _extentsX[c] = _fontSize >> 2;
                    GL.EndList();
                }
                return;
            }

            // Incorporate glyph bitmap bytes into managed code.
            byte[] currentGlyphBitmapBytes = new byte[size];
            uint   glyphWidth = (uint)(((long)bitmapglyphStructure.root.advance.x) / 65536);

            Marshal.Copy(bitmapglyphStructure.bitmap.buffer, currentGlyphBitmapBytes, 0, currentGlyphBitmapBytes.Length);

            // Expand the 8bpp anti-aliased pixmap to 16bpp, because target texture format shall be PixelInternalFormat.Rgba
            // (which is 4bpp R, 4bpp G, 4bpp B and 4bpp A) and source pixel data should have the same bpp.
            // Since source pixel data are 8bpp gray-scale (interpreted as PixelFormat.Luminance) just double them to be
            // interpreted as PixelFormat.LuminanceAlpha, which is loassless gray-scale 16bpp (8bpp luminance/8bppalpha).
            uint expandedBitmapWidth  = RoundUpToNextPowerOf2(bitmapglyphStructure.bitmap.width);
            uint expandedBitmapHeight = RoundUpToNextPowerOf2(bitmapglyphStructure.bitmap.rows);

            byte[] expandedBitmapBytes = new byte[2 * expandedBitmapWidth * expandedBitmapHeight];
            for (int countY = 0; countY < expandedBitmapHeight; countY++)
            {
                for (int countX = 0; countX < expandedBitmapWidth; countX++)
                {
                    // Since a glyph bitmap is 8bpp anti-aliased (gray-scale) pixmap, the new bitmap can assume luminance == alpha.
                    expandedBitmapBytes[2 * (countX + countY * expandedBitmapWidth)]         =
                        expandedBitmapBytes[2 * (countX + countY * expandedBitmapWidth) + 1] =
                            (countX >= bitmapglyphStructure.bitmap.width || countY >= bitmapglyphStructure.bitmap.rows) ?
                            (byte)0 : currentGlyphBitmapBytes[countX + bitmapglyphStructure.bitmap.width * countY];
                }
            }

            // Set up some texture parameters for opengl.
            GL.BindTexture(TextureTarget.Texture2D, _textures[c]);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);

            // Create the texture.
            GL.TexImage2D(TextureTarget.Texture2D, /*level-of-detail*/ 0, /*texture-format 32bit*/ PixelInternalFormat.Rgba,
                          /*texture-width*/ (int)expandedBitmapWidth, /*texture-height*/ (int)expandedBitmapHeight, /*border*/ 0,
                          /*pixel-data-format*/ PixelFormat.LuminanceAlpha, /*pixel-data-type*/ PixelType.UnsignedByte, expandedBitmapBytes);
            expandedBitmapBytes     = null;
            currentGlyphBitmapBytes = null;

            // ---------------------------------------------------------------------------
            //Create a display list (of precompiled GL commands) and bind a texture to it.
            GL.NewList((uint)(_listBase + c), ListMode.Compile);
            GL.BindTexture(TextureTarget.Texture2D, _textures[c]);

            // Account for freetype spacing rules.
            GL.Translate((int)bitmapglyphStructure.left, 0, 0);
            GL.PushMatrix();
            //var top = (int)bitmapglyphStructure.bitmap.rows - (int)bitmapglyphStructure.top;
            var height = bitmapglyphStructure.bitmap.rows;
            var top    = (int)bitmapglyphStructure.top;

            GL.Translate(0, -top, 0);
            //GL.Translate (Math.Max (0.0, (glyphWidth - bitmapglyphStructure.bitmap.width) / 2.0), (int)bitmapglyphStructure.top - (int)bitmapglyphStructure.bitmap.rows, 0);
            float x = bitmapglyphStructure.bitmap.width / (float)expandedBitmapWidth;
            float y = bitmapglyphStructure.bitmap.rows / (float)expandedBitmapHeight;

            // Draw the quad.
            GL.Begin(PrimitiveType.Quads);
            GL.TexCoord2(0, 0); GL.Vertex2(0, 0);
            GL.TexCoord2(x, 0); GL.Vertex2(bitmapglyphStructure.bitmap.width, 0);
            GL.TexCoord2(x, y); GL.Vertex2(bitmapglyphStructure.bitmap.width, bitmapglyphStructure.bitmap.rows);
            GL.TexCoord2(0, y); GL.Vertex2(0, bitmapglyphStructure.bitmap.rows);
            GL.End();

            GL.PopMatrix();


            // Advance for the next character.
            if (!_monospace)
            {
                GL.Translate(bitmapglyphStructure.bitmap.width, 0, 0);
            }
            else
            {
                GL.Translate(glyphWidth, 0, 0);
            }
            GL.EndList();
            // ---------------------------------------------------------------------------
            _extentsX[c] = (int)bitmapglyphStructure.left + (int)bitmapglyphStructure.bitmap.width;

            // Clean up the bitmap glyph memory.
            Glyph.FT_Done_Glyph(glyphPointer);
        }