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#include "wrap_Font.h"
22
23#include "Font.h"
24#include "freetype/Font.h"
25
26#include "wrap_GlyphData.h"
27#include "wrap_Rasterizer.h"
28
29#include "filesystem/wrap_Filesystem.h"
30
31namespace love
32{
33namespace font
34{
35
36#define instance() (Module::getInstance<Font>(Module::M_FONT))
37
38int w_newRasterizer(lua_State *L)
39{
40 if (lua_type(L, 1) == LUA_TNUMBER || lua_type(L, 2) == LUA_TNUMBER || lua_isnone(L, 1))
41 {
42 // First or second argument is a number: call newTrueTypeRasterizer.
43 return w_newTrueTypeRasterizer(L);
44 }
45 else if (lua_isnoneornil(L, 2))
46 {
47 // Single argument of another type: call Font::newRasterizer.
48 Rasterizer *t = nullptr;
49 filesystem::FileData *d = filesystem::luax_getfiledata(L, 1);
50
51 luax_catchexcept(L,
52 [&]() { t = instance()->newRasterizer(d); },
53 [&](bool) { d->release(); }
54 );
55
56 luax_pushtype(L, t);
57 t->release();
58 return 1;
59 }
60 else
61 {
62 // Otherwise call newBMFontRasterizer.
63 return w_newBMFontRasterizer(L);
64 }
65}
66
67int w_newTrueTypeRasterizer(lua_State *L)
68{
69 Rasterizer *t = nullptr;
70 TrueTypeRasterizer::Hinting hinting = TrueTypeRasterizer::HINTING_NORMAL;
71
72 if (lua_type(L, 1) == LUA_TNUMBER || lua_isnone(L, 1))
73 {
74 // First argument is a number: use the default TrueType font.
75 int size = (int) luaL_optinteger(L, 1, 12);
76
77 const char *hintstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2);
78 if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting))
79 return luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(hinting), hintstr);
80
81 if (lua_isnoneornil(L, 3))
82 luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, hinting); });
83 else
84 {
85 float dpiscale = (float) luaL_checknumber(L, 3);
86 luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, dpiscale, hinting); });
87 }
88 }
89 else
90 {
91 love::Data *d = nullptr;
92
93 if (luax_istype(L, 1, love::Data::type))
94 {
95 d = data::luax_checkdata(L, 1);
96 d->retain();
97 }
98 else
99 d = filesystem::luax_getfiledata(L, 1);
100
101 int size = (int) luaL_optinteger(L, 2, 12);
102
103 const char *hintstr = lua_isnoneornil(L, 3) ? nullptr : luaL_checkstring(L, 3);
104 if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting))
105 return luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(hinting), hintstr);
106
107 if (lua_isnoneornil(L, 4))
108 {
109 luax_catchexcept(L,
110 [&]() { t = instance()->newTrueTypeRasterizer(d, size, hinting); },
111 [&](bool) { d->release(); }
112 );
113 }
114 else
115 {
116 float dpiscale = (float) luaL_checknumber(L, 4);
117 luax_catchexcept(L,
118 [&]() { t = instance()->newTrueTypeRasterizer(d, size, dpiscale, hinting); },
119 [&](bool) { d->release(); }
120 );
121 }
122 }
123
124 luax_pushtype(L, t);
125 t->release();
126 return 1;
127}
128
129static void convimagedata(lua_State *L, int idx)
130{
131 if (lua_type(L, 1) == LUA_TSTRING || luax_istype(L, idx, love::filesystem::File::type) || luax_istype(L, idx, love::filesystem::FileData::type))
132 luax_convobj(L, idx, "image", "newImageData");
133}
134
135int w_newBMFontRasterizer(lua_State *L)
136{
137 Rasterizer *t = nullptr;
138
139 filesystem::FileData *d = filesystem::luax_getfiledata(L, 1);
140 std::vector<image::ImageData *> images;
141 float dpiscale = (float) luaL_optnumber(L, 3, 1.0);
142
143 if (lua_istable(L, 2))
144 {
145 for (int i = 1; i <= (int) luax_objlen(L, 2); i++)
146 {
147 lua_rawgeti(L, 2, i);
148
149 convimagedata(L, -1);
150 image::ImageData *id = luax_checktype<image::ImageData>(L, -1);
151 images.push_back(id);
152 id->retain();
153
154 lua_pop(L, 1);
155 }
156 }
157 else
158 {
159 convimagedata(L, 2);
160 image::ImageData *id = luax_checktype<image::ImageData>(L, 2);
161 images.push_back(id);
162 id->retain();
163 }
164
165 luax_catchexcept(L,
166 [&]() { t = instance()->newBMFontRasterizer(d, images, dpiscale); },
167 [&](bool) { d->release(); for (auto id : images) id->release(); }
168 );
169
170 luax_pushtype(L, t);
171 t->release();
172 return 1;
173}
174
175int w_newImageRasterizer(lua_State *L)
176{
177 Rasterizer *t = nullptr;
178
179 convimagedata(L, 1);
180
181 image::ImageData *d = luax_checktype<image::ImageData>(L, 1);
182 std::string glyphs = luax_checkstring(L, 2);
183 int extraspacing = (int) luaL_optinteger(L, 3, 0);
184 float dpiscale = (float) luaL_optnumber(L, 4, 1.0);
185
186 luax_catchexcept(L, [&](){ t = instance()->newImageRasterizer(d, glyphs, extraspacing, dpiscale); });
187
188 luax_pushtype(L, t);
189 t->release();
190 return 1;
191}
192
193int w_newGlyphData(lua_State *L)
194{
195 Rasterizer *r = luax_checkrasterizer(L, 1);
196 GlyphData *t = nullptr;
197
198 // newGlyphData accepts a unicode character or a codepoint number.
199 if (lua_type(L, 2) == LUA_TSTRING)
200 {
201 std::string glyph = luax_checkstring(L, 2);
202 luax_catchexcept(L, [&](){ t = instance()->newGlyphData(r, glyph); });
203 }
204 else
205 {
206 uint32 g = (uint32) luaL_checknumber(L, 2);
207 t = instance()->newGlyphData(r, g);
208 }
209
210 luax_pushtype(L, t);
211 t->release();
212 return 1;
213}
214
215// List of functions to wrap.
216static const luaL_Reg functions[] =
217{
218 { "newRasterizer", w_newRasterizer },
219 { "newTrueTypeRasterizer", w_newTrueTypeRasterizer },
220 { "newBMFontRasterizer", w_newBMFontRasterizer },
221 { "newImageRasterizer", w_newImageRasterizer },
222 { "newGlyphData", w_newGlyphData },
223 { 0, 0 }
224};
225
226static const lua_CFunction types[] =
227{
228 luaopen_glyphdata,
229 luaopen_rasterizer,
230 0
231};
232
233extern "C" int luaopen_love_font(lua_State *L)
234{
235 Font *instance = instance();
236 if (instance == nullptr)
237 {
238 luax_catchexcept(L, [&](){ instance = new freetype::Font(); });
239 }
240 else
241 instance->retain();
242
243 WrappedModule w;
244 w.module = instance;
245 w.name = "font";
246 w.type = &Module::type;
247 w.functions = functions;
248 w.types = types;
249
250 return luax_register_module(L, w);
251}
252
253} // font
254} // love
255