1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21// LOVE
22#include "common/config.h"
23#include "wrap_Font.h"
24
25// C++
26#include <algorithm>
27
28namespace love
29{
30namespace graphics
31{
32
33void luax_checkcoloredstring(lua_State *L, int idx, std::vector<Font::ColoredString> &strings)
34{
35 Font::ColoredString coloredstr;
36 coloredstr.color = Colorf(1.0f, 1.0f, 1.0f, 1.0f);
37
38 if (lua_istable(L, idx))
39 {
40 int len = (int) luax_objlen(L, idx);
41
42 for (int i = 1; i <= len; i++)
43 {
44 lua_rawgeti(L, idx, i);
45
46 if (lua_istable(L, -1))
47 {
48 for (int j = 1; j <= 4; j++)
49 lua_rawgeti(L, -j, j);
50
51 coloredstr.color.r = (float) luaL_checknumber(L, -4);
52 coloredstr.color.g = (float) luaL_checknumber(L, -3);
53 coloredstr.color.b = (float) luaL_checknumber(L, -2);
54 coloredstr.color.a = (float) luaL_optnumber(L, -1, 1.0);
55
56 lua_pop(L, 4);
57 }
58 else
59 {
60 coloredstr.str = luaL_checkstring(L, -1);
61 strings.push_back(coloredstr);
62 }
63
64 lua_pop(L, 1);
65 }
66 }
67 else
68 {
69 coloredstr.str = luaL_checkstring(L, idx);
70 strings.push_back(coloredstr);
71 }
72}
73
74Font *luax_checkfont(lua_State *L, int idx)
75{
76 return luax_checktype<Font>(L, idx);
77}
78
79int w_Font_getHeight(lua_State *L)
80{
81 Font *t = luax_checkfont(L, 1);
82 lua_pushnumber(L, t->getHeight());
83 return 1;
84}
85
86int w_Font_getWidth(lua_State *L)
87{
88 Font *t = luax_checkfont(L, 1);
89 const char *str = luaL_checkstring(L, 2);
90 luax_catchexcept(L, [&](){ lua_pushinteger(L, t->getWidth(str)); });
91 return 1;
92}
93
94int w_Font_getWrap(lua_State *L)
95{
96 Font *t = luax_checkfont(L, 1);
97
98 std::vector<Font::ColoredString> text;
99 luax_checkcoloredstring(L, 2, text);
100
101 float wrap = (float) luaL_checknumber(L, 3);
102 int max_width = 0;
103 std::vector<std::string> lines;
104 std::vector<int> widths;
105
106 luax_catchexcept(L, [&]() { t->getWrap(text, wrap, lines, &widths); });
107
108 for (int width : widths)
109 max_width = std::max(max_width, width);
110
111 lua_pushinteger(L, max_width);
112 lua_createtable(L, (int) lines.size(), 0);
113
114 for (int i = 0; i < (int) lines.size(); i++)
115 {
116 lua_pushstring(L, lines[i].c_str());
117 lua_rawseti(L, -2, i + 1);
118 }
119
120 return 2;
121}
122
123int w_Font_setLineHeight(lua_State *L)
124{
125 Font *t = luax_checkfont(L, 1);
126 float h = (float)luaL_checknumber(L, 2);
127 t->setLineHeight(h);
128 return 0;
129}
130
131int w_Font_getLineHeight(lua_State *L)
132{
133 Font *t = luax_checkfont(L, 1);
134 lua_pushnumber(L, t->getLineHeight());
135 return 1;
136}
137
138int w_Font_setFilter(lua_State *L)
139{
140 Font *t = luax_checkfont(L, 1);
141 Texture::Filter f = t->getFilter();
142
143 const char *minstr = luaL_checkstring(L, 2);
144 const char *magstr = luaL_optstring(L, 3, minstr);
145
146 if (!Texture::getConstant(minstr, f.min))
147 return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr);
148 if (!Texture::getConstant(magstr, f.mag))
149 return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr);
150
151 f.anisotropy = (float) luaL_optnumber(L, 4, 1.0);
152
153 luax_catchexcept(L, [&](){ t->setFilter(f); });
154 return 0;
155}
156
157int w_Font_getFilter(lua_State *L)
158{
159 Font *t = luax_checkfont(L, 1);
160 const Texture::Filter f = t->getFilter();
161 const char *minstr;
162 const char *magstr;
163 Texture::getConstant(f.min, minstr);
164 Texture::getConstant(f.mag, magstr);
165 lua_pushstring(L, minstr);
166 lua_pushstring(L, magstr);
167 lua_pushnumber(L, f.anisotropy);
168 return 3;
169}
170
171int w_Font_getAscent(lua_State *L)
172{
173 Font *t = luax_checkfont(L, 1);
174 lua_pushnumber(L, t->getAscent());
175 return 1;
176}
177
178int w_Font_getDescent(lua_State *L)
179{
180 Font *t = luax_checkfont(L, 1);
181 lua_pushnumber(L, t->getDescent());
182 return 1;
183}
184
185int w_Font_getBaseline(lua_State *L)
186{
187 Font *t = luax_checkfont(L, 1);
188 lua_pushnumber(L, t->getBaseline());
189 return 1;
190}
191
192int w_Font_hasGlyphs(lua_State *L)
193{
194 Font *t = luax_checkfont(L, 1);
195 bool hasglyph = false;
196
197 int count = std::max(lua_gettop(L) - 1, 1);
198
199 luax_catchexcept(L, [&]() {
200 for (int i = 2; i < count + 2; i++)
201 {
202 if (lua_type(L, i) == LUA_TSTRING)
203 hasglyph = t->hasGlyphs(luax_checkstring(L, i));
204 else
205 hasglyph = t->hasGlyph((uint32) luaL_checknumber(L, i));
206
207 if (!hasglyph)
208 break;
209 }
210 });
211
212 luax_pushboolean(L, hasglyph);
213 return 1;
214}
215
216int w_Font_getKerning(lua_State *L)
217{
218 Font *t = luax_checkfont(L, 1);
219 float kerning = 0.0f;
220
221 luax_catchexcept(L, [&]() {
222 if (lua_type(L, 2) == LUA_TSTRING)
223 {
224 std::string left = luax_checkstring(L, 2);
225 std::string right = luax_checkstring(L, 3);
226 kerning = t->getKerning(left, right);
227 }
228 else
229 {
230 uint32 left = (uint32) luaL_checknumber(L, 2);
231 uint32 right = (uint32) luaL_checknumber(L, 3);
232 kerning = t->getKerning(left, right);
233 }
234 });
235
236 lua_pushnumber(L, kerning);
237 return 1;
238}
239
240int w_Font_setFallbacks(lua_State *L)
241{
242 Font *t = luax_checkfont(L, 1);
243 std::vector<graphics::Font *> fallbacks;
244
245 for (int i = 2; i <= lua_gettop(L); i++)
246 fallbacks.push_back(luax_checkfont(L, i));
247
248 luax_catchexcept(L, [&](){ t->setFallbacks(fallbacks); });
249 return 0;
250}
251
252int w_Font_getDPIScale(lua_State *L)
253{
254 Font *t = luax_checkfont(L, 1);
255 lua_pushnumber(L, t->getDPIScale());
256 return 1;
257}
258
259static const luaL_Reg w_Font_functions[] =
260{
261 { "getHeight", w_Font_getHeight },
262 { "getWidth", w_Font_getWidth },
263 { "getWrap", w_Font_getWrap },
264 { "setLineHeight", w_Font_setLineHeight },
265 { "getLineHeight", w_Font_getLineHeight },
266 { "setFilter", w_Font_setFilter },
267 { "getFilter", w_Font_getFilter },
268 { "getAscent", w_Font_getAscent },
269 { "getDescent", w_Font_getDescent },
270 { "getBaseline", w_Font_getBaseline },
271 { "hasGlyphs", w_Font_hasGlyphs },
272 { "getKerning", w_Font_getKerning },
273 { "setFallbacks", w_Font_setFallbacks },
274 { "getDPIScale", w_Font_getDPIScale },
275 { 0, 0 }
276};
277
278extern "C" int luaopen_font(lua_State *L)
279{
280 return luax_register_type(L, &Font::type, w_Font_functions, nullptr);
281}
282
283} // graphics
284} // love
285