@@ -48,6 +48,7 @@ public sealed class FormeRenderer : IDisposable
4848 private RasterizerState ? _savedRasterizerState ;
4949 private SamplerState ? _savedSamplerState0 ;
5050 private SamplerState ? _savedSamplerState1 ;
51+ private SamplerState ? _savedSamplerState2 ;
5152
5253 private Matrix _transformMatrix ;
5354 private bool _hasCustomTransform ;
@@ -148,6 +149,7 @@ public void Begin(Matrix? transformMatrix = null)
148149 _savedRasterizerState = _graphicsDevice . RasterizerState ;
149150 _savedSamplerState0 = _graphicsDevice . SamplerStates [ 0 ] ;
150151 _savedSamplerState1 = _graphicsDevice . SamplerStates [ 1 ] ;
152+ _savedSamplerState2 = _graphicsDevice . SamplerStates [ 2 ] ;
151153
152154 if ( transformMatrix . HasValue )
153155 {
@@ -205,7 +207,7 @@ public void DrawString(FormeFontDevice font, string text, Vector2 position, floa
205207
206208 if ( font . Glyphs . TryGetValue ( rune . Value , out FormeGlyph glyph ) )
207209 {
208- _queue . Add ( new QueuedDraw ( font , glyph , new Vector2 ( cursorX , position . Y ) , sizePixels , color ) ) ;
210+ _queue . Add ( new QueuedDraw ( font , glyph , rune . Value , new Vector2 ( cursorX , position . Y ) , sizePixels , color ) ) ;
209211 cursorX += glyph . AdvanceWidth * scale ;
210212 }
211213 }
@@ -254,7 +256,7 @@ public void DrawString(FormeFontDevice font, string text, Vector2 position, floa
254256 }
255257
256258 Vector2 glyphPos = new ( position . X + placement . BaselineX , position . Y + placement . BaselineY ) ;
257- _queue . Add ( new QueuedDraw ( font , glyph , glyphPos , sizePixels , color ) ) ;
259+ _queue . Add ( new QueuedDraw ( font , glyph , placement . CodePoint , glyphPos , sizePixels , color ) ) ;
258260 }
259261 }
260262
@@ -289,7 +291,7 @@ public void DrawGlyph(FormeFontDevice font, int codepoint, Vector2 position, flo
289291
290292 if ( font . Glyphs . TryGetValue ( codepoint , out FormeGlyph glyph ) )
291293 {
292- _queue . Add ( new QueuedDraw ( font , glyph , position , sizePixels , color ) ) ;
294+ _queue . Add ( new QueuedDraw ( font , glyph , codepoint , position , sizePixels , color ) ) ;
293295 }
294296 }
295297
@@ -318,6 +320,7 @@ public void End()
318320 _graphicsDevice . RasterizerState = RasterizerState . CullNone ;
319321 _graphicsDevice . SamplerStates [ 0 ] = SamplerState . PointClamp ;
320322 _graphicsDevice . SamplerStates [ 1 ] = SamplerState . PointClamp ;
323+ _graphicsDevice . SamplerStates [ 2 ] = SamplerState . PointClamp ;
321324
322325 FormeFontDevice ? currentFont = null ;
323326 _glyphCount = 0 ;
@@ -354,6 +357,7 @@ public void End()
354357 _graphicsDevice . RasterizerState = _savedRasterizerState ! ;
355358 _graphicsDevice . SamplerStates [ 0 ] = _savedSamplerState0 ! ;
356359 _graphicsDevice . SamplerStates [ 1 ] = _savedSamplerState1 ! ;
360+ _graphicsDevice . SamplerStates [ 2 ] = _savedSamplerState2 ! ;
357361 }
358362
359363 private void FlushBatch ( FormeFontDevice font )
@@ -379,6 +383,7 @@ private void FlushBatch(FormeFontDevice font)
379383 _effect . Parameters [ "forme_matrix" ] . SetValue ( matrix ) ;
380384 _effect . Parameters [ "curveTexture" ] . SetValue ( font . CurveTexture ) ;
381385 _effect . Parameters [ "bandTexture" ] . SetValue ( font . BandTexture ) ;
386+ _effect . Parameters [ "bandLUTTexture" ] . SetValue ( font . BandLutTexture ) ;
382387
383388 // curveTexSize and bandTexSize are used by the OpenGL shader for UV-based texel
384389 // sampling but are not present in the DirectX 11 shader, which uses Load() instead.
@@ -433,11 +438,6 @@ private bool AppendGlyphQuad(in QueuedDraw draw)
433438 float ex1 = g . BoundingBox . X2 ;
434439 float ey1 = g . BoundingBox . Y2 ;
435440
436- float bandScaleX = 1.0f / Math . Max ( 1f , ( float ) g . BandInfo . DimX ) ;
437- float bandScaleY = 1.0f / Math . Max ( 1f , ( float ) g . BandInfo . DimY ) ;
438- float bandOffsetX = - ( float ) g . BoundingBox . X1 * bandScaleX ;
439- float bandOffsetY = - ( float ) g . BoundingBox . Y1 * bandScaleY ;
440-
441441 // Pack band texture origin using the texture width as the row stride.
442442 // The shader unpacks this using the runtime uniform bandTexSize.x, avoiding
443443 // compile-time constant folding that the MGCB/MojoShader transpiler gets wrong.
@@ -456,7 +456,15 @@ private bool AppendGlyphQuad(in QueuedDraw draw)
456456 draw . Color . B / 255f ,
457457 draw . Color . A / 255f ) ;
458458
459- Vector4 bnd = new Vector4 ( bandScaleX , bandScaleY , bandOffsetX , bandOffsetY ) ;
459+ // Inverse Jacobian: maps a screen-space displacement to an em-space displacement.
460+ float invJxx = ( ex1 - ex0 ) / ( px1 - px0 ) ;
461+ float invJyy = ( ey0 - ey1 ) / ( py1 - py0 ) ; // negative; font Y up, screen Y down
462+
463+ Vector2 lutUV = draw . Font . GlyphLutUVs . TryGetValue ( draw . CodePoint , out Vector2 uv )
464+ ? uv
465+ : Vector2 . Zero ;
466+
467+ Vector4 dilation = new Vector4 ( lutUV . X , lutUV . Y , invJxx , invJyy ) ;
460468
461469 int baseVertex = _glyphCount * 4 ;
462470
@@ -465,31 +473,31 @@ private bool AppendGlyphQuad(in QueuedDraw draw)
465473 Pos = new Vector4 ( px0 , py0 , - InvSqrt2 , - InvSqrt2 ) ,
466474 Tex = new Vector4 ( ex0 , ey1 , packedBandTexLoc , packedBandCount ) ,
467475 Color = color ,
468- Bnd = bnd
476+ Dilation = dilation
469477 } ;
470478
471479 _vertices [ baseVertex + 1 ] = new FormeVertex
472480 {
473481 Pos = new Vector4 ( px1 , py0 , InvSqrt2 , - InvSqrt2 ) ,
474482 Tex = new Vector4 ( ex1 , ey1 , packedBandTexLoc , packedBandCount ) ,
475483 Color = color ,
476- Bnd = bnd
484+ Dilation = dilation
477485 } ;
478486
479487 _vertices [ baseVertex + 2 ] = new FormeVertex
480488 {
481489 Pos = new Vector4 ( px1 , py1 , InvSqrt2 , InvSqrt2 ) ,
482490 Tex = new Vector4 ( ex1 , ey0 , packedBandTexLoc , packedBandCount ) ,
483491 Color = color ,
484- Bnd = bnd
492+ Dilation = dilation
485493 } ;
486494
487495 _vertices [ baseVertex + 3 ] = new FormeVertex
488496 {
489497 Pos = new Vector4 ( px0 , py1 , - InvSqrt2 , InvSqrt2 ) ,
490498 Tex = new Vector4 ( ex0 , ey0 , packedBandTexLoc , packedBandCount ) ,
491499 Color = color ,
492- Bnd = bnd
500+ Dilation = dilation
493501 } ;
494502
495503 int baseIndex = _glyphCount * 6 ;
@@ -534,14 +542,16 @@ private readonly struct QueuedDraw
534542 {
535543 internal FormeFontDevice Font { get ; }
536544 internal FormeGlyph Glyph { get ; }
545+ internal int CodePoint { get ; }
537546 internal Vector2 Position { get ; }
538547 internal float SizePixels { get ; }
539548 internal Color Color { get ; }
540549
541- internal QueuedDraw ( FormeFontDevice font , FormeGlyph glyph , Vector2 position , float sizePixels , Color color )
550+ internal QueuedDraw ( FormeFontDevice font , FormeGlyph glyph , int codePoint , Vector2 position , float sizePixels , Color color )
542551 {
543552 Font = font ;
544553 Glyph = glyph ;
554+ CodePoint = codePoint ;
545555 Position = position ;
546556 SizePixels = sizePixels ;
547557 Color = color ;
0 commit comments