-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFontDisplayService.lua
More file actions
310 lines (235 loc) · 8.25 KB
/
Copy pathFontDisplayService.lua
File metadata and controls
310 lines (235 loc) · 8.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
-- FontDisplayService
local fds = {}
local out = {}
local FontCreator = require(script.Parent.FontCreator)
--
--
local wordCharactersString = 'abcdefghijklmnopqrstuvwxyz.?!1234567890/-\'";:,[]{}()<>'
local wordCharacters = {}; for i=1, #wordCharactersString do local char=wordCharactersString:sub(i,i) wordCharacters[char:lower()]=true end
--
--
setmetatable(out, {
__index = function(out, index)
if fds[index] then
return fds[index]
else
error(tostring(index)..' is not a valid member of fontDisplayService')
end
end,
__newindex = function(out, index, value)
error('fontDisplayService.'..tostring(index)..' cannot be set')
end
})
--
--
function findInString(str, text)
local startingIndex = 0
local checkingIndex = 1
for i=1, #str do
if str:sub(i,i) == text:sub(checkingIndex, checkingIndex) then
if checkingIndex == 2 then
startingIndex = i-1
end
if checkingIndex == #text then
--print('found "' .. text .. '" in "' .. str .. '" at ' .. startingIndex .. 'x' .. i) wait()
return startingIndex, i
end
checkingIndex = checkingIndex + 1
end
end
return nil
end
--
--
local ContentProvider = game:GetService 'ContentProvider'
function fds:Preload(name)
local source = FontCreator.load(name).source
ContentProvider:Preload(source)
end
--
--
function fds:WriteToFrame(fontname, size, text, wraps, frame, wordDetectionEnabled)
local font = FontCreator.load(fontname)
local maxBounds = Vector2.new()
local currentPosition = Vector2.new(0, 0)
local wrappingBounds = frame.AbsoluteSize
local sizeMultiplierX = size/font.baseHeight
local wraps = wraps and true or false
local wordDetectionEnabled = wordDetectionEnabled and true or false
local currentWord = ''
local currentWordPosition = Vector2.new(0, 0)
local currentWordSpecialLocations = {}
local specialCases = {} -- int index = string charname
local visualCharacters = {}
--
-- load special cases
for charname, bounds in pairs( font.chars ) do
if #charname > 1 then
local s='bbccabcc'
local case='cc'
local start, fin = s:find(case) s=s:gsub(s:sub(1, fin), s:sub(1, start-1)..'t')
local start, fin = findInString(text, charname)
while start ~= nil do
-- text = text:gsub(
-- text:sub(1, fin),
-- text:sub(1, start-1)..'_'
-- )
-- If you don't understand it, just write it yourself
text = text:sub(1, start-1) .. '_' .. text:sub(fin+1)
-- print(text)
specialCases[start] = charname
start, fin = findInString(text, charname)
end
end
end
--
--
local tryAddCharacter = function(charSize)
if wraps == true and (currentPosition + charSize).x > wrappingBounds.x then
currentPosition = Vector2.new(0, currentPosition.y + font.letterSpacing*sizeMultiplierX + size + font.lineSpacing*sizeMultiplierX)
else
currentPosition = currentPosition + charSize
end
-- maxBounds = Vector2.new( -- doing this in post
-- math.max((currentPosition + charSize).x, maxBounds.x),
-- currentPosition.y + size
-- )
end
local addCharacter = function(char)
--[[if char == ' ' or char == '\t' then
local unitLength = (char == ' ' and 1) or (char == '\t' and 3)
local realSize = (font.spaceWidth+font.letterSpacing)*unitLength*sizeMultiplierX
tryAddCharacter(Vector2.new(realSize, 0))
else --]]
if char == '\n' then
-- don't get why we're adding letterspacing in there
currentPosition = Vector2.new(0, currentPosition.y + font.info.spacing[1]*sizeMultiplierX + size + font.common.lineHeight*sizeMultiplierX)
-- currentPosition = Vector2.new(0, currentPosition.y + font.letterSpacing*sizeMultiplierX + size + font.lineSpacing*sizeMultiplierX)
else
local bounds = font.getCharBounds(char)
--print(char, #char, char:byte())
local sizeMultiplierY = sizeMultiplierX*(1/(bounds.height/font.baseHeight))
local relativeSize = Vector2.new(bounds.width*sizeMultiplierX, bounds.height*sizeMultiplierX)--sizeMultiplierY)
-- now that I know how this works, it occurs to me an alternative would be to build imagelabels
-- for each character and simply clone them here
local visual = Instance.new 'ImageLabel'
visual.Name = tostring(#visualCharacters+1)
visual.BackgroundTransparency = 1
visual.Image = "rbxgameasset://Images/"..font.info.font
visual.ImageRectOffset = Vector2.new(bounds.x, bounds.y)
visual.ImageRectSize = Vector2.new(bounds.width, bounds.height)
visual.Position = UDim2.new(0, currentPosition.x, 0, currentPosition.y)
visual.Size = UDim2.new(0, relativeSize.x, 0, relativeSize.y)
-- visual.Parent = frame
visual.ZIndex = frame.ZIndex
table.insert(visualCharacters, visual)
tryAddCharacter(Vector2.new(relativeSize.x + (font.info.spacing[1]*sizeMultiplierX), 0))
--
-- do extension
-- local ext = font.extensions[char]
if true then --ext ~= nil then
--local top, bottom = unpack(ext)
--local top, bottom = top or 0, bottom or 0
--visual.ImageRectOffset = visual.ImageRectOffset + Vector2.new(0, -top)
--visual.ImageRectSize = visual.ImageRectSize + Vector2.new(0, top+bottom)
visual.Position = visual.Position + UDim2.new(0, 0, 0, sizeMultiplierX*bounds.yoffset )---top)
--visual.Size = visual.Size + UDim2.new(0, 0, 0, sizeMultiplierY*(bounds.height+bounds.yoffset))--top+bottom))
end
end
end
local addWord = function()
-- print('adding word "' .. currentWord .. '"')
local wordSize = font.getStringSize(currentWord, size)
if wraps == true and wordDetectionEnabled == true and (currentWordPosition + wordSize).x > wrappingBounds.x then
if currentWordPosition.x > 0 then
currentPosition = Vector2.new(0, currentWordPosition.y + font.info.spacing[1]*sizeMultiplierX + size + font.common.lineHeight*sizeMultiplierX)
else
currentPosition = currentWordPosition
end
else
currentPosition = currentWordPosition
end
--
-- setup special info
local specialStartingLocations = {} -- int start = vector2 size
for specialSize, char in next, currentWordSpecialLocations do
specialStartingLocations[specialSize.x] = specialSize
end
--
--
for index=1, #currentWord do
local specialSize = specialStartingLocations[index]
if specialSize then
local diff = specialSize.y - specialSize.x
currentWord = currentWord:sub(1, specialSize.x-1) .. '_' .. currentWord:sub(specialSize.y)
local specialChar = currentWordSpecialLocations[specialSize]
addCharacter(specialChar)
--
-- fix up the specialStartingLocations
local diffv2 = Vector2.new(diff, 0)
for specialSize, char in next, currentWordSpecialLocations do
local v2 = specialSize - diffv2
currentWordSpecialLocations[v2] = char
specialStartingLocations[specialSize.x - diff] = v2
end
else
if index <= #currentWord then
addCharacter(currentWord:sub(index,index))
end
end
end
--
--
currentWord = ''
currentWordPosition = currentPosition
currentWordSpecialLocations = {}
end
for index=1, #text do
local char = text:sub(index, index)
local isSpecial = false
if specialCases[index] ~= nil then
char = specialCases[index]
isSpecial = true
end
if wordCharacters[char:lower()] == true or font.specialWordCharacters[char] == true then
currentWord = currentWord .. char
if isSpecial then
currentWordSpecialLocations[Vector2.new(#currentWord-#char+1, #currentWord+1)] = char
end
if currentWord == char then -- char is the first letter, set a new currentWordPosition
currentWordPosition = currentPosition
end
currentPosition = currentPosition + Vector2.new(font.getStringSize(char, size), 0)
else
if currentWord ~= '' then -- need to write the current word
addWord()
end
addCharacter(char)
end
end
if currrentWord ~= '' then -- there's still a word waiting to be written
addWord()
end
--
-- ugly hack ahead since I can't figure out what's up with word detection not being accounted for when calculating max bounds
if true then
maxBounds = Vector2.new()
for index, visual in next, visualCharacters do
maxBounds = Vector2.new(
math.max(maxBounds.x, visual.Position.X.Offset+visual.Size.X.Offset),
math.max(maxBounds.y, visual.Position.Y.Offset+visual.Size.Y.Offset)
)
end
end
--
-- now parent all the frames.
for index, visual in next, visualCharacters do
visual.Parent = frame
end
--
--
return maxBounds
end
--
--
return out