/// <summary> /// Returns next power-of-two size if required by render system, in case /// RSC_NON_POWER_OF_2_TEXTURES is supported it returns value as-is. /// </summary> /// <param name="value"></param> /// <returns></returns> public static int OptionalPO2(int value) { RenderSystemCapabilities caps = Root.Instance.RenderSystem.Capabilities; if (caps.HasCapability(Capabilities.NonPowerOf2Textures)) { return(value); } else { return((int)Bitwise.FirstPO2From((uint)value)); } }
public void LoadResource(Resource res) { // TODO : Revisit after checking current Imaging support in Mono. #if !(XBOX || XBOX360 || ANDROID || IPHONE || SILVERLIGHT) var current = Environment.CurrentDirectory; var ftLibrary = IntPtr.Zero; if (FT.FT_Init_FreeType(out ftLibrary) != 0) { throw new AxiomException("Could not init FreeType library!"); } var face = IntPtr.Zero; // Add a gap between letters vert and horz // prevents nasty artefacts when letters are too close together var char_space = 5; // Locate ttf file, load it pre-buffered into memory by wrapping the // original DataStream in a MemoryDataStream var fileStream = ResourceGroupManager.Instance.OpenResource(Source, Group, true, this); var ttfchunk = new byte[fileStream.Length]; fileStream.Read(ttfchunk, 0, ttfchunk.Length); //Load font if (FT.FT_New_Memory_Face(ftLibrary, ttfchunk, ttfchunk.Length, 0, out face) != 0) { throw new AxiomException("Could not open font face!"); } // Convert our point size to freetype 26.6 fixed point format var ftSize = this._ttfSize * (1 << 6); if (FT.FT_Set_Char_Size(face, ftSize, 0, (uint)this._ttfResolution, (uint)this._ttfResolution) != 0) { throw new AxiomException("Could not set char size!"); } int max_height = 0, max_width = 0; // Backwards compatibility - if codepoints not supplied, assume 33-166 if (this.codePointRange.Count == 0) { this.codePointRange.Add(new KeyValuePair <int, int>(33, 166)); } // Calculate maximum width, height and bearing var glyphCount = 0; foreach (var r in this.codePointRange) { var range = r; for (var cp = range.Key; cp <= range.Value; ++cp, ++glyphCount) { FT.FT_Load_Char(face, (uint)cp, 4); //4 == FT_LOAD_RENDER var rec = face.PtrToStructure <FT_FaceRec>(); var glyp = rec.glyph.PtrToStructure <FT_GlyphSlotRec>(); if ((2 * (glyp.bitmap.rows << 6) - glyp.metrics.horiBearingY) > max_height) { max_height = (2 * (glyp.bitmap.rows << 6) - glyp.metrics.horiBearingY); } if (glyp.metrics.horiBearingY > this.maxBearingY) { this.maxBearingY = glyp.metrics.horiBearingY; } if ((glyp.advance.x >> 6) + (glyp.metrics.horiBearingX >> 6) > max_width) { max_width = (glyp.advance.x >> 6) + (glyp.metrics.horiBearingX >> 6); } } } // Now work out how big our texture needs to be var rawSize = (max_width + char_space) * ((max_height >> 6) + char_space) * glyphCount; var tex_side = (int)System.Math.Sqrt((Real)rawSize); // just in case the size might chop a glyph in half, add another glyph width/height tex_side += System.Math.Max(max_width, (max_height >> 6)); // Now round up to nearest power of two var roundUpSize = (int)Bitwise.FirstPO2From((uint)tex_side); // Would we benefit from using a non-square texture (2X width) int finalWidth = 0, finalHeight = 0; if (roundUpSize * roundUpSize * 0.5 >= rawSize) { finalHeight = (int)(roundUpSize * 0.5); } else { finalHeight = roundUpSize; } finalWidth = roundUpSize; var textureAspec = (Real)finalWidth / (Real)finalHeight; var pixelBytes = 2; var dataWidth = finalWidth * pixelBytes; var dataSize = finalWidth * finalHeight * pixelBytes; LogManager.Instance.Write("Font {0} using texture size {1}x{2}", _name, finalWidth.ToString(), finalHeight.ToString()); var imageData = new byte[dataSize]; // Reset content (White, transparent) for (var i = 0; i < dataSize; i += pixelBytes) { imageData[i + 0] = 0xff; // luminance imageData[i + 1] = 0x00; // alpha } int l = 0, m = 0; foreach (var r in this.codePointRange) { var range = r; for (var cp = range.Key; cp <= range.Value; ++cp) { // Load & render glyph var ftResult = FT.FT_Load_Char(face, (uint)cp, 4); //4 == FT_LOAD_RENDER if (ftResult != 0) { // problem loading this glyph, continue LogManager.Instance.Write("Info: cannot load character '{0}' in font {1}.", #if (SILVERLIGHT || WINDOWS_PHONE) cp, #else char.ConvertFromUtf32(cp), #endif _name); continue; } var rec = face.PtrToStructure <FT_FaceRec>(); var glyp = rec.glyph.PtrToStructure <FT_GlyphSlotRec>(); var advance = glyp.advance.x >> 6; if (glyp.bitmap.buffer == IntPtr.Zero) { LogManager.Instance.Write("Info: Freetype returned null for character '{0} in font {1}.", #if (SILVERLIGHT || WINDOWS_PHONE) cp, #else char.ConvertFromUtf32(cp), #endif _name); continue; } #if !AXIOM_SAFE_ONLY unsafe #endif { var buffer = BufferBase.Wrap(glyp.bitmap.buffer, glyp.bitmap.rows * glyp.bitmap.pitch); var bufferPtr = buffer.ToBytePointer(); var idx = 0; var imageDataBuffer = BufferBase.Wrap(imageData); var imageDataPtr = imageDataBuffer.ToBytePointer(); var y_bearing = ((this.maxBearingY >> 6) - (glyp.metrics.horiBearingY >> 6)); var x_bearing = glyp.metrics.horiBearingX >> 6; for (var j = 0; j < glyp.bitmap.rows; j++) { var row = j + m + y_bearing; var pDest = (row * dataWidth) + (l + x_bearing) * pixelBytes; for (var k = 0; k < glyp.bitmap.width; k++) { if (AntialiasColor) { // Use the same greyscale pixel for all components RGBA imageDataPtr[pDest++] = bufferPtr[idx]; } else { // Always white whether 'on' or 'off' pixel, since alpha // will turn off imageDataPtr[pDest++] = (byte)0xFF; } // Always use the greyscale value for alpha imageDataPtr[pDest++] = bufferPtr[idx++]; } //end k } //end j buffer.Dispose(); imageDataBuffer.Dispose(); SetGlyphTexCoords((uint)cp, (Real)l / (Real)finalWidth, //u1 (Real)m / (Real)finalHeight, //v1 (Real)(l + (glyp.advance.x >> 6)) / (Real)finalWidth, //u2 (m + (max_height >> 6)) / (Real)finalHeight, //v2 textureAspec); // Advance a column l += (advance + char_space); // If at end of row if (finalWidth - 1 < l + (advance)) { m += (max_height >> 6) + char_space; l = 0; } } } } //end foreach var memStream = new MemoryStream(imageData); var img = Image.FromRawStream(memStream, finalWidth, finalHeight, PixelFormat.BYTE_LA); var tex = (Texture)res; // Call internal _loadImages, not loadImage since that's external and // will determine load status etc again, and this is a manual loader inside load() var images = new Image[1]; images[0] = img; tex.LoadImages(images); FT.FT_Done_FreeType(ftLibrary); //img.Save( "C:" + Path.DirectorySeparatorChar + Name + ".png" ); //FileStream file = new FileStream( "C:" + Path.DirectorySeparatorChar + Name + ".fontdef", FileMode.Create ); //StreamWriter str = new StreamWriter( file ); //str.WriteLine( Name ); //str.WriteLine( "{" ); //str.WriteLine( "\ttype\timage" ); //str.WriteLine( "\tsource\t{0}.png\n", Name ); //for ( uint i = 0; i < (uint)( END_CHAR - START_CHAR ); i++ ) //{ // char c = (char)( i + START_CHAR ); // str.WriteLine( "\tglyph\t{0}\t{1:F6}\t{2:F6}\t{3:F6}\t{4:F6}", c, Glyphs[ c ].uvRect.Top, Glyphs[ c ].uvRect.Left, Glyphs[ c ].uvRect.Bottom, Glyphs[ c ].uvRect.Right ); //} //str.WriteLine( "}" ); //str.Close(); //file.Close(); #endif }