comparison semiconginev2/old/resources/font.nim @ 1218:56781cc0fc7c compiletime-tests

did: renamge main package
author sam <sam@basx.dev>
date Wed, 17 Jul 2024 21:01:37 +0700
parents semicongine/old/resources/font.nim@a3eb305bcac2
children
comparison
equal deleted inserted replaced
1217:f819a874058f 1218:56781cc0fc7c
1 import std/tables
2 import std/strutils
3 import std/strformat
4 import std/streams
5 import std/os
6 import std/unicode
7 import std/logging
8
9 import ../core/vector
10 import ../core/imagetypes
11 import ../core/fonttypes
12 import ../algorithms
13
14 {.emit: "#define STBTT_STATIC".}
15 {.emit: "#define STB_TRUETYPE_IMPLEMENTATION".}
16 {.emit: "#include \"" & currentSourcePath.parentDir() & "/stb_truetype.h\"".}
17
18 type stbtt_fontinfo {.importc, incompleteStruct.} = object
19
20 proc stbtt_InitFont(info: ptr stbtt_fontinfo, data: ptr char, offset: cint): cint {.importc, nodecl.}
21 proc stbtt_ScaleForPixelHeight(info: ptr stbtt_fontinfo, pixels: cfloat): cfloat {.importc, nodecl.}
22
23 proc stbtt_GetCodepointBitmap(info: ptr stbtt_fontinfo, scale_x: cfloat, scale_y: cfloat, codepoint: cint, width, height, xoff, yoff: ptr cint): cstring {.importc, nodecl.}
24 # proc stbtt_GetCodepointBitmapBox(info: ptr stbtt_fontinfo, codepoint: cint, scale_x, scale_y: cfloat, ix0, iy0, ix1, iy1: ptr cint) {.importc, nodecl.}
25
26 proc stbtt_GetCodepointHMetrics(info: ptr stbtt_fontinfo, codepoint: cint, advance, leftBearing: ptr cint) {.importc, nodecl.}
27 proc stbtt_GetCodepointKernAdvance(info: ptr stbtt_fontinfo, ch1, ch2: cint): cint {.importc, nodecl.}
28 proc stbtt_FindGlyphIndex(info: ptr stbtt_fontinfo, codepoint: cint): cint {.importc, nodecl.}
29
30 proc stbtt_GetFontVMetrics(info: ptr stbtt_fontinfo, ascent, descent, lineGap: ptr cint) {.importc, nodecl.}
31
32 proc free(p: pointer) {.importc.}
33
34 proc ReadTrueType*(stream: Stream, name: string, codePoints: seq[Rune], lineHeightPixels: float32): Font =
35 var
36 indata = stream.readAll()
37 fontinfo: stbtt_fontinfo
38 if stbtt_InitFont(addr fontinfo, addr indata[0], 0) == 0:
39 raise newException(Exception, "An error occured while loading PNG file")
40
41 result.name = name
42 result.fontscale = float32(stbtt_ScaleForPixelHeight(addr fontinfo, cfloat(lineHeightPixels)))
43
44 var ascent, descent, lineGap: cint
45 stbtt_GetFontVMetrics(addr fontinfo, addr ascent, addr descent, addr lineGap)
46
47 result.lineHeight = float32(ascent - descent) * result.fontscale
48 result.lineAdvance = float32(ascent - descent + lineGap) * result.fontscale
49
50 # ensure all codepoints are available in the font
51 for codePoint in codePoints:
52 if stbtt_FindGlyphIndex(addr fontinfo, cint(codePoint)) == 0:
53 warn &"Loading font {name}: Codepoint '{codePoint}' ({cint(codePoint)}) has no glyph"
54
55 var
56 topOffsets: Table[Rune, int]
57 images: seq[Image[GrayPixel]]
58 let empty_image = NewImage[GrayPixel](1, 1, [0'u8])
59
60 for codePoint in codePoints:
61 var
62 width, height: cint
63 offX, offY: cint
64 let
65 data = stbtt_GetCodepointBitmap(
66 addr fontinfo,
67 result.fontscale,
68 result.fontscale,
69 cint(codePoint),
70 addr width, addr height,
71 addr offX, addr offY
72 )
73 topOffsets[codePoint] = offY
74
75 if char(codePoint) in UppercaseLetters:
76 result.capHeight = float32(height)
77 if codePoint == Rune('x'):
78 result.xHeight = float32(height)
79
80 if width > 0 and height > 0:
81 var bitmap = newSeq[GrayPixel](width * height)
82 for i in 0 ..< width * height:
83 bitmap[i] = GrayPixel(data[i])
84 images.add NewImage[GrayPixel](width.uint32, height.uint32, bitmap)
85 else:
86 images.add empty_image
87
88 free(data)
89
90 let packed = Pack(images)
91
92 result.fontAtlas = Texture(
93 name: name & "_texture",
94 isGrayscale: true,
95 grayImage: packed.atlas,
96 sampler: FONTSAMPLER_SOFT,
97 )
98
99 let w = float32(packed.atlas.width)
100 let h = float32(packed.atlas.height)
101 for i in 0 ..< codePoints.len:
102 let
103 codePoint = codePoints[i]
104 image = images[i]
105 coord = (x: float32(packed.coords[i].x), y: float32(packed.coords[i].y))
106 iw = float32(image.width)
107 ih = float32(image.height)
108 # horizontal spaces:
109 var advance, leftBearing: cint
110 stbtt_GetCodepointHMetrics(addr fontinfo, cint(codePoint), addr advance, addr leftBearing)
111
112 result.glyphs[codePoint] = GlyphInfo(
113 dimension: NewVec2f(float32(image.width), float32(image.height)),
114 uvs: [
115 NewVec2f((coord.x + 0.5) / w, (coord.y + ih - 0.5) / h),
116 NewVec2f((coord.x + 0.5) / w, (coord.y + 0.5) / h),
117 NewVec2f((coord.x + iw - 0.5) / w, (coord.y + 0.5) / h),
118 NewVec2f((coord.x + iw - 0.5) / w, (coord.y + ih - 0.5) / h),
119 ],
120 topOffset: float32(topOffsets[codePoint]),
121 leftOffset: float32(leftBearing) * result.fontscale,
122 advance: float32(advance) * result.fontscale,
123 )
124
125 for codePointAfter in codePoints:
126 result.kerning[(codePoint, codePointAfter)] = float32(stbtt_GetCodepointKernAdvance(
127 addr fontinfo,
128 cint(codePoint),
129 cint(codePointAfter)
130 )) * result.fontscale