private unsafe DynamicAtlas <Color> .Reservation Upload(FTBitmap bitmap) { bool foundRoom = false; DynamicAtlas <Color> .Reservation result = default(DynamicAtlas <Color> .Reservation); int width = bitmap.Width, rows = bitmap.Rows, pitch = bitmap.Pitch; var widthW = width + (Font.GlyphMargin * 2); var heightW = rows + (Font.GlyphMargin * 2); foreach (var atlas in Atlases) { if (atlas.TryReserve(widthW, heightW, out result)) { foundRoom = true; break; } } var surfaceFormat = Font.sRGB ? Evil.TextureUtils.ColorSrgbEXT : SurfaceFormat.Color; if (!foundRoom) { var isFirstAtlas = (Atlases.Count == 0) && (_SizePoints < SmallFirstAtlasThreshold); var newAtlas = new DynamicAtlas <Color>( Font.RenderCoordinator, isFirstAtlas ? FirstAtlasWidth : AtlasWidth, isFirstAtlas ? FirstAtlasHeight : AtlasHeight, surfaceFormat, 4, Font.MipMapping ? PickMipGenerator(Font) : null, tag: $"{Font.Face.FamilyName} {SizePoints}pt" ); Atlases.Add(newAtlas); if (!newAtlas.TryReserve(widthW, heightW, out result)) { throw new InvalidOperationException("Character too large for atlas"); } } var pSrc = (byte *)bitmap.Buffer; fixed(Color *pPixels = result.Atlas.Pixels) { var pDest = (byte *)pPixels; switch (bitmap.PixelMode) { case PixelMode.Gray: var table = Font.GammaRamp?.GammaTable; var srgb = (surfaceFormat != SurfaceFormat.Color); for (var y = 0; y < rows; y++) { var rowOffset = result.Atlas.Width * (y + result.Y + Font.GlyphMargin) + (result.X + Font.GlyphMargin); var pDestRow = pDest + (rowOffset * 4); int yPitch = y * pitch; if (table == null) { for (var x = 0; x < width; x++) { var a = pSrc[x + yPitch]; var g = srgb ? ColorSpace.LinearByteTosRGBByteTable[a] : a; pDestRow[3] = a; pDestRow[2] = pDestRow[1] = pDestRow[0] = g; pDestRow += 4; } } else { for (var x = 0; x < width; x++) { var a = table[pSrc[x + yPitch]]; var g = srgb ? ColorSpace.LinearByteTosRGBByteTable[a] : a; pDestRow[3] = a; pDestRow[2] = pDestRow[1] = pDestRow[0] = g; pDestRow += 4; } } } break; case PixelMode.Mono: for (var y = 0; y < rows; y++) { var rowOffset = result.Atlas.Width * (y + result.Y + Font.GlyphMargin) + (result.X + Font.GlyphMargin); var pDestRow = pDest + (rowOffset * 4); int yPitch = y * pitch; for (int x = 0; x < pitch; x++, pDestRow += (8 * 4)) { var bits = pSrc[x + yPitch]; for (int i = 0; i < 8; i++) { int iy = 7 - i; byte g = ((bits & (1 << iy)) != 0) ? (byte)255 : (byte)0; var pElt = pDestRow + (i * 4); pElt[3] = pElt[2] = pElt[1] = pElt[0] = g; } } } break; default: throw new NotImplementedException("Unsupported pixel mode: " + bitmap.PixelMode); } } result.Invalidate(); return(result); }
private unsafe DynamicAtlas <Color> .Reservation Upload(FTBitmap bitmap) { bool foundRoom = false; DynamicAtlas <Color> .Reservation result = default(DynamicAtlas <Color> .Reservation); int width = bitmap.Width, rows = bitmap.Rows, pitch = bitmap.Pitch; var widthW = width + (Font.GlyphMargin * 2); var heightW = rows + (Font.GlyphMargin * 2); foreach (var atlas in Atlases) { if (atlas.TryReserve(widthW, heightW, out result)) { foundRoom = true; break; } } if (!foundRoom) { var newAtlas = new DynamicAtlas <Color>( Font.RenderCoordinator, AtlasWidth, AtlasHeight, SurfaceFormat.Color, 4, Font.MipMapping ? PickMipGenerator(Font) : null ); Atlases.Add(newAtlas); if (!newAtlas.TryReserve(widthW, heightW, out result)) { throw new InvalidOperationException("Character too large for atlas"); } } var pSrc = (byte *)bitmap.Buffer; fixed(Color *pPixels = result.Atlas.Pixels) { var pDest = (byte *)pPixels; switch (bitmap.PixelMode) { case PixelMode.Gray: var table = Font.GammaTable; for (var y = 0; y < rows; y++) { var rowOffset = result.Atlas.Width * (y + result.Y + Font.GlyphMargin) + (result.X + Font.GlyphMargin); var pDestRow = pDest + (rowOffset * 4); int yPitch = y * pitch; for (var x = 0; x < width; x++) { var g = table[pSrc[x + yPitch]]; pDestRow[3] = pDestRow[2] = pDestRow[1] = pDestRow[0] = g; pDestRow += 4; } } break; case PixelMode.Mono: for (var y = 0; y < rows; y++) { var rowOffset = result.Atlas.Width * (y + result.Y + Font.GlyphMargin) + (result.X + Font.GlyphMargin); var pDestRow = pDest + (rowOffset * 4); int yPitch = y * pitch; for (int x = 0; x < pitch; x++, pDestRow += (8 * 4)) { var bits = pSrc[x + yPitch]; for (int i = 0; i < 8; i++) { int iy = 7 - i; byte g = ((bits & (1 << iy)) != 0) ? (byte)255 : (byte)0; var pElt = pDestRow + (i * 4); pElt[3] = pElt[2] = pElt[1] = pElt[0] = g; } } } break; default: throw new NotImplementedException("Unsupported pixel mode: " + bitmap.PixelMode); } } return(result); }