FontAtlas.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. using FontStashSharp.Interfaces;
  2. using System;
  3. #if MONOGAME || FNA
  4. using Microsoft.Xna.Framework;
  5. using Microsoft.Xna.Framework.Graphics;
  6. #elif STRIDE
  7. using Stride.Graphics;
  8. using Stride.Core.Mathematics;
  9. using Texture2D = Stride.Graphics.Texture;
  10. #else
  11. using Texture2D = Veldrid.Texture;
  12. using System.Drawing;
  13. #endif
  14. namespace FontStashSharp
  15. {
  16. public class FontAtlas
  17. {
  18. byte[] _byteBuffer;
  19. byte[] _colorBuffer;
  20. public int Width { get; private set; }
  21. public int Height { get; private set; }
  22. public int NodesNumber { get; private set; }
  23. internal FontAtlasNode[] Nodes { get; private set; }
  24. public Texture2D Texture { get; set; }
  25. public FontAtlas(int w, int h, int count, Texture2D texture)
  26. {
  27. Width = w;
  28. Height = h;
  29. Texture = texture;
  30. Nodes = new FontAtlasNode[count];
  31. Nodes[0].X = 0;
  32. Nodes[0].Y = 0;
  33. Nodes[0].Width = w;
  34. NodesNumber++;
  35. }
  36. public void InsertNode(int idx, int x, int y, int w)
  37. {
  38. if (NodesNumber + 1 > Nodes.Length)
  39. {
  40. var oldNodes = Nodes;
  41. var newLength = Nodes.Length == 0 ? 8 : Nodes.Length * 2;
  42. Nodes = new FontAtlasNode[newLength];
  43. for (var i = 0; i < oldNodes.Length; ++i)
  44. {
  45. Nodes[i] = oldNodes[i];
  46. }
  47. }
  48. for (var i = NodesNumber; i > idx; i--)
  49. Nodes[i] = Nodes[i - 1];
  50. Nodes[idx].X = x;
  51. Nodes[idx].Y = y;
  52. Nodes[idx].Width = w;
  53. NodesNumber++;
  54. }
  55. public void RemoveNode(int idx)
  56. {
  57. if (NodesNumber == 0)
  58. return;
  59. for (var i = idx; i < NodesNumber - 1; i++)
  60. Nodes[i] = Nodes[i + 1];
  61. NodesNumber--;
  62. }
  63. public void Reset(int w, int h)
  64. {
  65. Width = w;
  66. Height = h;
  67. NodesNumber = 0;
  68. Nodes[0].X = 0;
  69. Nodes[0].Y = 0;
  70. Nodes[0].Width = w;
  71. NodesNumber++;
  72. }
  73. public bool AddSkylineLevel(int idx, int x, int y, int w, int h)
  74. {
  75. InsertNode(idx, x, y + h, w);
  76. for (var i = idx + 1; i < NodesNumber; i++)
  77. if (Nodes[i].X < Nodes[i - 1].X + Nodes[i - 1].Width)
  78. {
  79. var shrink = Nodes[i - 1].X + Nodes[i - 1].Width - Nodes[i].X;
  80. Nodes[i].X += shrink;
  81. Nodes[i].Width -= shrink;
  82. if (Nodes[i].Width <= 0)
  83. {
  84. RemoveNode(i);
  85. i--;
  86. }
  87. else
  88. {
  89. break;
  90. }
  91. }
  92. else
  93. {
  94. break;
  95. }
  96. for (var i = 0; i < NodesNumber - 1; i++)
  97. if (Nodes[i].Y == Nodes[i + 1].Y)
  98. {
  99. Nodes[i].Width += Nodes[i + 1].Width;
  100. RemoveNode(i + 1);
  101. i--;
  102. }
  103. return true;
  104. }
  105. public int RectFits(int i, int w, int h)
  106. {
  107. var x = Nodes[i].X;
  108. var y = Nodes[i].Y;
  109. if (x + w > Width)
  110. return -1;
  111. var spaceLeft = w;
  112. while (spaceLeft > 0)
  113. {
  114. if (i == NodesNumber)
  115. return -1;
  116. y = Math.Max(y, Nodes[i].Y);
  117. if (y + h > Height)
  118. return -1;
  119. spaceLeft -= Nodes[i].Width;
  120. ++i;
  121. }
  122. return y;
  123. }
  124. public bool AddRect(int rw, int rh, ref int rx, ref int ry)
  125. {
  126. var besth = Height;
  127. var bestw = Width;
  128. var besti = -1;
  129. var bestx = -1;
  130. var besty = -1;
  131. for (var i = 0; i < NodesNumber; i++)
  132. {
  133. var y = RectFits(i, rw, rh);
  134. if (y != -1)
  135. if (y + rh < besth || y + rh == besth && Nodes[i].Width < bestw)
  136. {
  137. besti = i;
  138. bestw = Nodes[i].Width;
  139. besth = y + rh;
  140. bestx = Nodes[i].X;
  141. besty = y;
  142. }
  143. }
  144. if (besti == -1)
  145. return false;
  146. if (!AddSkylineLevel(besti, bestx, besty, rw, rh))
  147. return false;
  148. rx = bestx;
  149. ry = besty;
  150. return true;
  151. }
  152. #if MONOGAME || FNA || STRIDE
  153. public void RenderGlyph(GraphicsDevice graphicsDevice, DynamicFontGlyph glyph, IFontSource fontSource, int blurAmount, int strokeAmount, bool premultiplyAlpha, int kernelWidth, int kernelHeight)
  154. #else
  155. public void RenderGlyph(ITexture2DManager textureManager, DynamicFontGlyph glyph, IFontSource fontSource, int blurAmount, int strokeAmount, bool premultiplyAlpha, int kernelWidth, int kernelHeight)
  156. #endif
  157. {
  158. if (glyph.IsEmpty)
  159. {
  160. return;
  161. }
  162. // Render glyph to byte buffer
  163. var bufferSize = glyph.Size.X * glyph.Size.Y;
  164. var buffer = _byteBuffer;
  165. if ((buffer == null) || (buffer.Length < bufferSize))
  166. {
  167. buffer = new byte[bufferSize];
  168. _byteBuffer = buffer;
  169. }
  170. Array.Clear(buffer, 0, bufferSize);
  171. var colorBuffer = _colorBuffer;
  172. var colorBufferSize = (glyph.Size.X + FontSystem.GlyphPad * 2) * (glyph.Size.Y + FontSystem.GlyphPad * 2) * 4;
  173. if ((colorBuffer == null) || (colorBuffer.Length < colorBufferSize))
  174. {
  175. colorBuffer = new byte[colorBufferSize * 4];
  176. _colorBuffer = colorBuffer;
  177. }
  178. // Create the atlas texture if required
  179. if (Texture == null)
  180. {
  181. #if MONOGAME || FNA || STRIDE
  182. Texture = Texture2DManager.CreateTexture(graphicsDevice, Width, Height);
  183. #else
  184. Texture = textureManager.CreateTexture(Width, Height);
  185. #endif
  186. }
  187. // Erase an area where we are going to place a glyph
  188. Array.Clear(colorBuffer, 0,colorBufferSize);
  189. var eraseArea = glyph.TextureRectangle;
  190. eraseArea.X = Math.Max(eraseArea.X - FontSystem.GlyphPad, 0);
  191. eraseArea.Y = Math.Max(eraseArea.Y - FontSystem.GlyphPad, 0);
  192. eraseArea.Width += FontSystem.GlyphPad * 2;
  193. if (eraseArea.Right > Width)
  194. {
  195. eraseArea.Width = Width - eraseArea.X;
  196. }
  197. eraseArea.Height += FontSystem.GlyphPad * 2;
  198. if (eraseArea.Bottom > Height)
  199. {
  200. eraseArea.Height = Height - eraseArea.Y;
  201. }
  202. #if MONOGAME || FNA || STRIDE
  203. Texture2DManager.SetTextureData(Texture, eraseArea, colorBuffer);
  204. #else
  205. textureManager.SetTextureData(Texture, eraseArea, colorBuffer);
  206. #endif
  207. var effectPad = Math.Max(blurAmount, strokeAmount);
  208. fontSource.RasterizeGlyphBitmap(glyph.Codepoint,
  209. glyph.FontSize,
  210. buffer,
  211. effectPad + effectPad * glyph.Size.X,
  212. glyph.Size.X - effectPad * 2,
  213. glyph.Size.Y - effectPad * 2,
  214. glyph.Size.X);
  215. if (strokeAmount > 0)
  216. {
  217. var width = glyph.Size.X;
  218. var top = width * strokeAmount;
  219. var bottom = (glyph.Size.Y - strokeAmount) * glyph.Size.X;
  220. var right = glyph.Size.X - strokeAmount;
  221. var left = strokeAmount;
  222. byte d;
  223. for (var i = 0; i < bufferSize; ++i)
  224. {
  225. var ci = i * 4;
  226. var col = buffer[i];
  227. var black = 0;
  228. if (col == 255)
  229. {
  230. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = colorBuffer[ci + 3] = 255;
  231. continue;
  232. }
  233. if (i >= top)
  234. black = buffer[i - top];
  235. if (i < bottom)
  236. {
  237. d = buffer[i + top];
  238. black = ((255 - d) * black + 255 * d) / 255;
  239. }
  240. if (i % width >= left)
  241. {
  242. d = buffer[i - strokeAmount];
  243. black = ((255 - d) * black + 255 * d) / 255;
  244. }
  245. if (i % width < right)
  246. {
  247. d = buffer[i + strokeAmount];
  248. black = ((255 - d) * black + 255 * d) / 255;
  249. }
  250. if (black == 0)
  251. {
  252. if (col == 0)
  253. {
  254. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = colorBuffer[ci + 3] = 0; //black transparency to suit stroke
  255. continue;
  256. }
  257. if (premultiplyAlpha)
  258. {
  259. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = colorBuffer[ci + 3] = col;
  260. }
  261. else
  262. {
  263. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = 255;
  264. colorBuffer[ci + 3] = col;
  265. }
  266. }
  267. else
  268. {
  269. if (col == 0)
  270. {
  271. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = 0;
  272. colorBuffer[ci + 3] = (byte)black;
  273. continue;
  274. }
  275. if (premultiplyAlpha)
  276. {
  277. var alpha = ((255 - col) * black + 255 * col) / 255;
  278. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = (byte)((alpha * col) / 255);
  279. colorBuffer[ci + 3] = (byte)alpha;
  280. }
  281. else
  282. {
  283. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = col;
  284. colorBuffer[ci + 3] = (byte)(((255 - col) * black + 255 * col) / 255);
  285. }
  286. }
  287. }
  288. }
  289. else
  290. {
  291. if (blurAmount > 0)
  292. {
  293. Blur(buffer, glyph.Size.X, glyph.Size.Y, glyph.Size.X, blurAmount);
  294. }
  295. for (var i = 0; i < bufferSize; ++i)
  296. {
  297. var ci = i * 4;
  298. var c = buffer[i];
  299. if (premultiplyAlpha)
  300. {
  301. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = colorBuffer[ci + 3] = c;
  302. }
  303. else
  304. {
  305. colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = 255;
  306. colorBuffer[ci + 3] = c;
  307. }
  308. }
  309. }
  310. // Render glyph to texture
  311. #if MONOGAME || FNA || STRIDE
  312. Texture2DManager.SetTextureData(Texture, glyph.TextureRectangle, colorBuffer);
  313. #else
  314. textureManager.SetTextureData(Texture, glyph.TextureRectangle, colorBuffer);
  315. #endif
  316. }
  317. void Blur(byte[] dst, int w, int h, int dstStride, int blur)
  318. {
  319. int alpha;
  320. float sigma;
  321. if (blur < 1)
  322. return;
  323. sigma = blur * 0.57735f;
  324. alpha = (int)((1 << 16) * (1.0f - Math.Exp(-2.3f / (sigma + 1.0f))));
  325. BlurRows(dst, w, h, dstStride, alpha);
  326. BlurCols(dst, w, h, dstStride, alpha);
  327. BlurRows(dst, w, h, dstStride, alpha);
  328. BlurCols(dst, w, h, dstStride, alpha);
  329. }
  330. static void BlurCols(byte[] dst, int w, int h, int dstStride, int alpha)
  331. {
  332. int x;
  333. int y;
  334. int index = 0;
  335. for (y = 0; y < h; y++)
  336. {
  337. var z = 0;
  338. for (x = 1; x < w; x++)
  339. {
  340. z += (alpha * ((dst[index + x] << 7) - z)) >> 16;
  341. dst[index + x] = (byte)(z >> 7);
  342. }
  343. dst[index + w - 1] = 0;
  344. z = 0;
  345. for (x = w - 2; x >= 0; x--)
  346. {
  347. z += (alpha * ((dst[index + x] << 7) - z)) >> 16;
  348. dst[index + x] = (byte)(z >> 7);
  349. }
  350. dst[index] = 0;
  351. index += dstStride;
  352. }
  353. }
  354. static void BlurRows(byte[] dst, int w, int h, int dstStride, int alpha)
  355. {
  356. int x;
  357. int y;
  358. int index = 0;
  359. for (x = 0; x < w; x++)
  360. {
  361. var z = 0;
  362. for (y = dstStride; y < h * dstStride; y += dstStride)
  363. {
  364. z += (alpha * ((dst[index + y] << 7) - z)) >> 16;
  365. dst[index +y] = (byte)(z >> 7);
  366. }
  367. dst[index +(h - 1) * dstStride] = 0;
  368. z = 0;
  369. for (y = (h - 2) * dstStride; y >= 0; y -= dstStride)
  370. {
  371. z += (alpha * ((dst[index +y] << 7) - z)) >> 16;
  372. dst[index +y] = (byte)(z >> 7);
  373. }
  374. dst[index] = 0;
  375. ++index;
  376. }
  377. }
  378. }
  379. }