1
1
using System . Reflection ;
2
2
using System . Runtime . InteropServices ;
3
+ using Silk . NET . OpenGL ;
3
4
using StbTrueTypeSharp ;
4
5
5
6
namespace Flamui . Drawing ;
@@ -33,22 +34,12 @@ public ScaledFont(Font font, float pixelSize)
33
34
34
35
public float GetCharWidth ( char c )
35
36
{
36
- if ( Font . FontGlyphInfos . TryGetValue ( c , out var info ) )
37
- {
38
- return info . UnscaledAdvanceWidth * Scale ;
39
- }
40
-
41
- return 0 ;
37
+ return Font . GetGlyphInfo ( c ) . UnscaledAdvanceWidth * Scale ;
42
38
}
43
39
44
40
public int GetAdvanceWith ( char c )
45
41
{
46
- if ( Font . FontGlyphInfos . TryGetValue ( c , out var info ) )
47
- {
48
- return ( int ) ( info . UnscaledAdvanceWidth * Scale ) ;
49
- }
50
-
51
- return 0 ;
42
+ return ( int ) ( Font . GetGlyphInfo ( c ) . UnscaledAdvanceWidth * Scale ) ;
52
43
}
53
44
54
45
public float GetHeight ( ) => Ascent - Descent ;
@@ -68,7 +59,27 @@ public class Font
68
59
public required float UnscaledLineGap ;
69
60
public required StbTrueType . stbtt_fontinfo FontInfo ;
70
61
71
- public required Dictionary < char , FontGlyphInfo > FontGlyphInfos ;
62
+ private Dictionary < char , FontGlyphInfo > fontGlyphInfos = [ ] ;
63
+
64
+ public unsafe FontGlyphInfo GetGlyphInfo ( char c )
65
+ {
66
+ if ( fontGlyphInfos . TryGetValue ( c , out var info ) )
67
+ return info ;
68
+
69
+ int advanceWidth = 0 ;
70
+ int leftSideBearing = 0 ;
71
+
72
+ StbTrueType . stbtt_GetCodepointHMetrics ( FontInfo , c , & advanceWidth , & leftSideBearing ) ;
73
+
74
+ info = new FontGlyphInfo
75
+ {
76
+ UnscaledAdvanceWidth = advanceWidth ,
77
+ UnscaledLeftSideBearing = leftSideBearing
78
+ } ;
79
+
80
+ fontGlyphInfos [ c ] = info ;
81
+ return info ;
82
+ }
72
83
73
84
public float GetScale ( float pixelSize )
74
85
{
@@ -80,26 +91,79 @@ public float GetHeight(float scale)
80
91
return UnscaledAscent * scale - UnscaledDescent * scale ;
81
92
}
82
93
83
- public float GetCharWidth ( char c , float scale )
84
- {
85
- if ( FontGlyphInfos . TryGetValue ( c , out var info ) )
86
- {
87
- return info . UnscaledAdvanceWidth * scale ;
88
- }
89
-
90
- return 0 ;
91
- }
94
+ // public float GetCharWidth(char c, float scale)
95
+ // {
96
+ // if (FontGlyphInfos.TryGetValue(c, out var info))
97
+ // {
98
+ // return info.UnscaledAdvanceWidth * scale;
99
+ // }
100
+ //
101
+ // return 0;
102
+ // }
92
103
}
93
104
94
105
public class FontAtlas
95
106
{
96
107
public required ScaledFont Font ;
97
- public required byte [ ] AtlasBitmap ;
98
108
public required int AtlasWidth ;
99
109
public required int AtlasHeight ;
100
- public required Dictionary < char , AtlasGlyphInfo > GlyphInfos ;
101
110
102
111
public GpuTexture GpuTexture ;
112
+
113
+ public required LRUCache < char , AtlasGlyphInfo > Table ;
114
+
115
+ public unsafe AtlasGlyphInfo FindGlyphEntry ( char c , float resolutionMultiplier )
116
+ {
117
+ if ( Table . TryGet ( c , out var entry ) )
118
+ {
119
+ return entry ;
120
+ }
121
+
122
+ entry = Table . GetLeastUsed ( ) ;
123
+
124
+ int width = 0 ;
125
+ int height = 0 ;
126
+ int xOff = 0 ;
127
+ int yOff = 0 ;
128
+
129
+ var bitmap = StbTrueType . stbtt_GetCodepointBitmap ( Font . Font . FontInfo , 0 , Font . Scale * resolutionMultiplier , c ,
130
+ & width , & height , & xOff , & yOff ) ;
131
+ var bitmapSpan = new Span < byte > ( bitmap , width * height ) ;
132
+
133
+ for ( var i = 0 ; i < bitmapSpan . Length ; i ++ ) //correct upwards for clearer text, not sure why we need to do it...
134
+ {
135
+ ref var b = ref bitmapSpan [ i ] ;
136
+
137
+ var f = ( double ) b ;
138
+ f = 255 * Math . Pow ( f / 255 , 0.5f ) ;
139
+ b = ( byte ) f ;
140
+ }
141
+
142
+ GpuTexture . Gl . BindTexture ( TextureTarget . Texture2D , GpuTexture . TextureId ) ;
143
+ GpuTexture . Gl . PixelStore ( PixelStoreParameter . UnpackAlignment , 1 ) ;
144
+ GpuTexture . Gl . TexSubImage2D ( TextureTarget . Texture2D , 0 , entry . AtlasX , entry . AtlasY , ( uint ) width , ( uint ) height , PixelFormat . Red , PixelType . UnsignedByte , ( void * ) bitmap ) ;
145
+
146
+ Console . WriteLine ( $ "Uploading { c } at { entry . AtlasX } ,{ entry . AtlasY } ") ;
147
+
148
+ var info = new AtlasGlyphInfo
149
+ {
150
+ Height = height / resolutionMultiplier ,
151
+ Width = width / resolutionMultiplier ,
152
+ XOff = xOff / resolutionMultiplier ,
153
+ YOff = yOff / resolutionMultiplier ,
154
+ AtlasX = entry . AtlasX ,
155
+ AtlasY = entry . AtlasY ,
156
+ AtlasWidth = width ,
157
+ AtlasHeight = height ,
158
+ // GlyphBoundingBox = bb,
159
+ FontGlyphInfo = Font . Font . GetGlyphInfo ( c ) ,
160
+ Scale = Font . Scale
161
+ } ;
162
+
163
+ Table . Add ( c , info ) ;
164
+
165
+ return info ;
166
+ }
103
167
}
104
168
105
169
public struct FontGlyphInfo
@@ -128,22 +192,6 @@ public struct AtlasGlyphInfo
128
192
// public required GlyphBoundingBox GlyphBoundingBox;
129
193
}
130
194
131
- public unsafe struct CharInfo
132
- {
133
- public required byte * Bitmap ;
134
- public required int Width ;
135
- public required int Height ;
136
- public required int XOff ;
137
- public required int YOff ;
138
- public required char Char ;
139
-
140
-
141
- public Span < byte > BitmapAsSpan ( )
142
- {
143
- return new Span < byte > ( Bitmap , Width * Height ) ;
144
- }
145
- }
146
-
147
195
public class FontLoader
148
196
{
149
197
public static unsafe Font LoadFont ( string name )
@@ -169,22 +217,6 @@ public static unsafe Font LoadFont(string name)
169
217
int lineGap = 0 ;
170
218
StbTrueType . stbtt_GetFontVMetrics ( info , & ascent , & descent , & lineGap ) ;
171
219
172
- Dictionary < char , FontGlyphInfo > glyphInfos = new ( '~' - ' ' ) ;
173
-
174
- for ( char i = ' ' ; i < '~' ; i ++ )
175
- {
176
- int advanceWidth = 0 ;
177
- int leftSideBearing = 0 ;
178
-
179
- StbTrueType . stbtt_GetCodepointHMetrics ( info , i , & advanceWidth , & leftSideBearing ) ;
180
-
181
- glyphInfos [ i ] = new FontGlyphInfo
182
- {
183
- UnscaledAdvanceWidth = advanceWidth ,
184
- UnscaledLeftSideBearing = leftSideBearing
185
- } ;
186
- }
187
-
188
220
return new Font
189
221
{
190
222
Name = name ,
@@ -193,129 +225,33 @@ public static unsafe Font LoadFont(string name)
193
225
UnscaledDescent = descent ,
194
226
UnscaledLineGap = lineGap ,
195
227
FontInfo = info ,
196
- FontGlyphInfos = glyphInfos
197
228
} ;
198
229
}
199
230
200
- public static unsafe FontAtlas CreateFontAtlas ( ScaledFont scaledFont , float resolutionMultiplier )
231
+ public static FontAtlas CreateFontAtlas ( ScaledFont scaledFont )
201
232
{
202
- // var scale = StbTrueType.stbtt_ScaleForPixelHeight(font.FontInfo, pixelSize);
203
-
204
- int maxCharWidth = 0 ;
205
- int maxCharHeight = 0 ;
233
+ var table = new LRUCache < char , AtlasGlyphInfo > ( 10 * 10 ) ;
206
234
207
- CharInfo [ ] charInfos = new CharInfo [ '~' - ' ' ] ;
208
-
209
- for ( char i = ' ' ; i < '~' ; i ++ )
235
+ for ( int i = 1 ; i < 11 ; i ++ )
210
236
{
211
- int width = 0 ;
212
- int height = 0 ;
213
- int xOff = 0 ;
214
- int yOff = 0 ;
215
-
216
- var bitmap = StbTrueType . stbtt_GetCodepointBitmap ( scaledFont . Font . FontInfo , 0 , scaledFont . Scale * resolutionMultiplier , i , & width , & height , & xOff , & yOff ) ;
217
-
218
- maxCharHeight = Math . Max ( maxCharHeight , height ) ;
219
- maxCharWidth = Math . Max ( maxCharWidth , width ) ;
220
-
221
- charInfos [ i - ' ' ] = new CharInfo
237
+ for ( int j = 1 ; j < 11 ; j ++ )
222
238
{
223
- Bitmap = bitmap ,
224
- Width = width ,
225
- Height = height ,
226
- XOff = xOff ,
227
- YOff = yOff ,
228
- Char = i ,
229
- } ;
230
- }
231
-
232
- int rowColCount = ( int ) Math . Ceiling ( Math . Sqrt ( charInfos . Length ) ) ;
233
- int minAtlasWidth = rowColCount * maxCharHeight ;
234
- int minAtlasHeight = rowColCount * maxCharWidth ;
235
- int atlasSize = Math . Max ( minAtlasHeight , minAtlasWidth ) ;
236
- atlasSize = RoundUpToNextPowerOfTwo ( atlasSize ) ;
237
- //
238
- // if (atlasSize % 2 != 0)
239
- // {
240
- // atlasSize++;
241
- // }
242
- //todo make atalasSize even number
243
-
244
- byte [ ] fontAtlasBitmapData = new byte [ atlasSize * atlasSize ] ;
245
-
246
- BitRect fontAtlasBitmap = new BitRect
247
- {
248
- Data = fontAtlasBitmapData . AsSpan ( ) ,
249
- Height = atlasSize ,
250
- Width = atlasSize
251
- } ;
252
- var glyphInfos = new Dictionary < char , AtlasGlyphInfo > ( charInfos . Length ) ;
253
-
254
- int currentCol = 0 ;
255
- int currentRow = 0 ;
256
-
257
- for ( var i = 0 ; i < charInfos . Length ; i ++ )
258
- {
259
- var c = charInfos [ i ] ;
260
-
261
- // var bb = new GlyphBoundingBox();
262
-
263
- // StbTrueType.stbtt_GetCodepointBitmapBox(font.FontInfo, i, 0, scale, &bb.x0, &bb.y0, &bb.x1, &bb.y1);
264
-
265
- var bitmap = new BitRect
266
- {
267
- Data = c . BitmapAsSpan ( ) ,
268
- Height = c . Height ,
269
- Width = c . Width
270
- } ;
271
-
272
- int xOffset = currentCol * maxCharWidth ;
273
- int yOffset = currentRow * maxCharHeight ;
274
-
275
- Copy ( bitmap , fontAtlasBitmap , xOffset , yOffset ) ;
276
-
277
- glyphInfos [ c . Char ] = new AtlasGlyphInfo
278
- {
279
- Height = c . Height / resolutionMultiplier ,
280
- Width = c . Width / resolutionMultiplier ,
281
- XOff = c . XOff / resolutionMultiplier ,
282
- YOff = c . YOff / resolutionMultiplier ,
283
- AtlasX = xOffset ,
284
- AtlasY = yOffset ,
285
- AtlasWidth = c . Width ,
286
- AtlasHeight = c . Height ,
287
- // GlyphBoundingBox = bb,
288
- FontGlyphInfo = scaledFont . Font . FontGlyphInfos [ c . Char ] ,
289
- Scale = scaledFont . Scale
290
- } ;
291
-
292
- if ( currentCol == rowColCount - 1 )
293
- {
294
- currentCol = 0 ;
295
- currentRow ++ ;
296
- }
297
- else
298
- {
299
- currentCol ++ ;
239
+ table . Add ( ( char ) ( int . MaxValue - i - 100 * j ) , default ( AtlasGlyphInfo ) with
240
+ {
241
+ AtlasX = i * 100 ,
242
+ AtlasY = j * 100 ,
243
+ } ) ;
300
244
}
301
245
}
302
246
303
- for ( var i = 0 ; i < fontAtlasBitmapData . Length ; i ++ ) //correct upwards for clearer text, not sure why we need to do it...
304
- {
305
- ref var b = ref fontAtlasBitmapData [ i ] ;
306
-
307
- var f = ( double ) b ;
308
- f = 255 * Math . Pow ( f / 255 , 0.5f ) ;
309
- b = ( byte ) f ;
310
- }
311
-
312
247
return new FontAtlas
313
248
{
314
249
Font = scaledFont ,
315
- AtlasBitmap = fontAtlasBitmapData ,
316
- AtlasWidth = atlasSize ,
317
- AtlasHeight = atlasSize ,
318
- GlyphInfos = glyphInfos ,
250
+ // AtlasBitmap = fontAtlasBitmapData,
251
+ AtlasWidth = 1024 ,
252
+ AtlasHeight = 1024 ,
253
+ Table = table
254
+ // GlyphInfos = glyphInfos,
319
255
} ;
320
256
}
321
257
0 commit comments