1061b68a7SWarner Losh /*-
2061b68a7SWarner Losh * Copyright (c) 2024 Netflix, Inc.
3061b68a7SWarner Losh *
4061b68a7SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
5061b68a7SWarner Losh */
6061b68a7SWarner Losh
7061b68a7SWarner Losh /* Copied from a file that likely shoulve have had this at the top */
8061b68a7SWarner Losh /*-
9061b68a7SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
10061b68a7SWarner Losh *
11061b68a7SWarner Losh * Copyright 2020 Toomas Soome
12061b68a7SWarner Losh * Copyright 2020 RackTop Systems, Inc.
13061b68a7SWarner Losh *
14061b68a7SWarner Losh * Redistribution and use in source and binary forms, with or without
15061b68a7SWarner Losh * modification, are permitted provided that the following conditions
16061b68a7SWarner Losh * are met:
17061b68a7SWarner Losh * 1. Redistributions of source code must retain the above copyright
18061b68a7SWarner Losh * notice, this list of conditions and the following disclaimer.
19061b68a7SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright
20061b68a7SWarner Losh * notice, this list of conditions and the following disclaimer in the
21061b68a7SWarner Losh * documentation and/or other materials provided with the distribution.
22061b68a7SWarner Losh *
23061b68a7SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24061b68a7SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25061b68a7SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26061b68a7SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27061b68a7SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28061b68a7SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29061b68a7SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30061b68a7SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31061b68a7SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32061b68a7SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33061b68a7SWarner Losh * SUCH DAMAGE.
34061b68a7SWarner Losh */
35061b68a7SWarner Losh
36061b68a7SWarner Losh #include "lua.h"
37061b68a7SWarner Losh #include "lauxlib.h"
38061b68a7SWarner Losh #include "lutils.h"
39061b68a7SWarner Losh #include <gfx_fb.h>
40061b68a7SWarner Losh #include <pnglite.h>
41061b68a7SWarner Losh
42061b68a7SWarner Losh /*
43061b68a7SWarner Losh * put image using terminal coordinates.
44061b68a7SWarner Losh */
45061b68a7SWarner Losh static int
lua_term_putimage(lua_State * L)46061b68a7SWarner Losh lua_term_putimage(lua_State *L)
47061b68a7SWarner Losh {
48061b68a7SWarner Losh const char *name;
49061b68a7SWarner Losh png_t png;
50061b68a7SWarner Losh uint32_t x1, y1, x2, y2, f;
51061b68a7SWarner Losh int nargs, ret = 0, error;
52061b68a7SWarner Losh
53061b68a7SWarner Losh nargs = lua_gettop(L);
54061b68a7SWarner Losh if (nargs != 6) {
55061b68a7SWarner Losh lua_pushboolean(L, 0);
56061b68a7SWarner Losh return 1;
57061b68a7SWarner Losh }
58061b68a7SWarner Losh
59061b68a7SWarner Losh name = luaL_checkstring(L, 1);
60061b68a7SWarner Losh x1 = luaL_checknumber(L, 2);
61061b68a7SWarner Losh y1 = luaL_checknumber(L, 3);
62061b68a7SWarner Losh x2 = luaL_checknumber(L, 4);
63061b68a7SWarner Losh y2 = luaL_checknumber(L, 5);
64061b68a7SWarner Losh f = luaL_checknumber(L, 6);
65061b68a7SWarner Losh
66061b68a7SWarner Losh x1 = gfx_state.tg_origin.tp_col + x1 * gfx_state.tg_font.vf_width;
67061b68a7SWarner Losh y1 = gfx_state.tg_origin.tp_row + y1 * gfx_state.tg_font.vf_height;
68061b68a7SWarner Losh if (x2 != 0) {
69061b68a7SWarner Losh x2 = gfx_state.tg_origin.tp_col +
70061b68a7SWarner Losh x2 * gfx_state.tg_font.vf_width;
71061b68a7SWarner Losh }
72061b68a7SWarner Losh if (y2 != 0) {
73061b68a7SWarner Losh y2 = gfx_state.tg_origin.tp_row +
74061b68a7SWarner Losh y2 * gfx_state.tg_font.vf_height;
75061b68a7SWarner Losh }
76061b68a7SWarner Losh
77061b68a7SWarner Losh if ((error = png_open(&png, name)) != PNG_NO_ERROR) {
78061b68a7SWarner Losh if (f & FL_PUTIMAGE_DEBUG)
79061b68a7SWarner Losh printf("%s\n", png_error_string(error));
80061b68a7SWarner Losh } else {
81061b68a7SWarner Losh if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0)
82061b68a7SWarner Losh ret = 1;
83061b68a7SWarner Losh (void) png_close(&png);
84061b68a7SWarner Losh }
85061b68a7SWarner Losh lua_pushboolean(L, ret);
86061b68a7SWarner Losh return 1;
87061b68a7SWarner Losh }
88061b68a7SWarner Losh
89061b68a7SWarner Losh static int
lua_fb_putimage(lua_State * L)90061b68a7SWarner Losh lua_fb_putimage(lua_State *L)
91061b68a7SWarner Losh {
92061b68a7SWarner Losh const char *name;
93061b68a7SWarner Losh png_t png;
94061b68a7SWarner Losh uint32_t x1, y1, x2, y2, f;
95061b68a7SWarner Losh int nargs, ret = 0, error;
96061b68a7SWarner Losh
97061b68a7SWarner Losh nargs = lua_gettop(L);
98061b68a7SWarner Losh if (nargs != 6) {
99061b68a7SWarner Losh lua_pushboolean(L, 0);
100061b68a7SWarner Losh return 1;
101061b68a7SWarner Losh }
102061b68a7SWarner Losh
103061b68a7SWarner Losh name = luaL_checkstring(L, 1);
104061b68a7SWarner Losh x1 = luaL_checknumber(L, 2);
105061b68a7SWarner Losh y1 = luaL_checknumber(L, 3);
106061b68a7SWarner Losh x2 = luaL_checknumber(L, 4);
107061b68a7SWarner Losh y2 = luaL_checknumber(L, 5);
108061b68a7SWarner Losh f = luaL_checknumber(L, 6);
109061b68a7SWarner Losh
110061b68a7SWarner Losh if ((error = png_open(&png, name)) != PNG_NO_ERROR) {
111061b68a7SWarner Losh if (f & FL_PUTIMAGE_DEBUG)
112061b68a7SWarner Losh printf("%s\n", png_error_string(error));
113061b68a7SWarner Losh } else {
114061b68a7SWarner Losh if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0)
115061b68a7SWarner Losh ret = 1;
116061b68a7SWarner Losh (void) png_close(&png);
117061b68a7SWarner Losh }
118061b68a7SWarner Losh lua_pushboolean(L, ret);
119061b68a7SWarner Losh return 1;
120061b68a7SWarner Losh }
121061b68a7SWarner Losh
122061b68a7SWarner Losh static int
lua_fb_setpixel(lua_State * L)123061b68a7SWarner Losh lua_fb_setpixel(lua_State *L)
124061b68a7SWarner Losh {
125061b68a7SWarner Losh uint32_t x, y;
126061b68a7SWarner Losh int nargs;
127061b68a7SWarner Losh
128061b68a7SWarner Losh nargs = lua_gettop(L);
129061b68a7SWarner Losh if (nargs != 2) {
130061b68a7SWarner Losh lua_pushnil(L);
131061b68a7SWarner Losh return 1;
132061b68a7SWarner Losh }
133061b68a7SWarner Losh
134061b68a7SWarner Losh x = luaL_checknumber(L, 1);
135061b68a7SWarner Losh y = luaL_checknumber(L, 2);
136061b68a7SWarner Losh gfx_fb_setpixel(x, y);
137061b68a7SWarner Losh return 0;
138061b68a7SWarner Losh }
139061b68a7SWarner Losh
140061b68a7SWarner Losh static int
lua_fb_line(lua_State * L)141061b68a7SWarner Losh lua_fb_line(lua_State *L)
142061b68a7SWarner Losh {
143061b68a7SWarner Losh uint32_t x0, y0, x1, y1, wd;
144061b68a7SWarner Losh int nargs;
145061b68a7SWarner Losh
146061b68a7SWarner Losh nargs = lua_gettop(L);
147061b68a7SWarner Losh if (nargs != 5) {
148061b68a7SWarner Losh lua_pushnil(L);
149061b68a7SWarner Losh return 1;
150061b68a7SWarner Losh }
151061b68a7SWarner Losh
152061b68a7SWarner Losh x0 = luaL_checknumber(L, 1);
153061b68a7SWarner Losh y0 = luaL_checknumber(L, 2);
154061b68a7SWarner Losh x1 = luaL_checknumber(L, 3);
155061b68a7SWarner Losh y1 = luaL_checknumber(L, 4);
156061b68a7SWarner Losh wd = luaL_checknumber(L, 5);
157061b68a7SWarner Losh gfx_fb_line(x0, y0, x1, y1, wd);
158061b68a7SWarner Losh return 0;
159061b68a7SWarner Losh }
160061b68a7SWarner Losh
161061b68a7SWarner Losh static int
lua_fb_bezier(lua_State * L)162061b68a7SWarner Losh lua_fb_bezier(lua_State *L)
163061b68a7SWarner Losh {
164061b68a7SWarner Losh uint32_t x0, y0, x1, y1, x2, y2, width;
165061b68a7SWarner Losh int nargs;
166061b68a7SWarner Losh
167061b68a7SWarner Losh nargs = lua_gettop(L);
168061b68a7SWarner Losh if (nargs != 7) {
169061b68a7SWarner Losh lua_pushnil(L);
170061b68a7SWarner Losh return 1;
171061b68a7SWarner Losh }
172061b68a7SWarner Losh
173061b68a7SWarner Losh x0 = luaL_checknumber(L, 1);
174061b68a7SWarner Losh y0 = luaL_checknumber(L, 2);
175061b68a7SWarner Losh x1 = luaL_checknumber(L, 3);
176061b68a7SWarner Losh y1 = luaL_checknumber(L, 4);
177061b68a7SWarner Losh x2 = luaL_checknumber(L, 5);
178061b68a7SWarner Losh y2 = luaL_checknumber(L, 6);
179061b68a7SWarner Losh width = luaL_checknumber(L, 7);
180061b68a7SWarner Losh gfx_fb_bezier(x0, y0, x1, y1, x2, y2, width);
181061b68a7SWarner Losh return 0;
182061b68a7SWarner Losh }
183061b68a7SWarner Losh
184061b68a7SWarner Losh static int
lua_fb_drawrect(lua_State * L)185061b68a7SWarner Losh lua_fb_drawrect(lua_State *L)
186061b68a7SWarner Losh {
187061b68a7SWarner Losh uint32_t x0, y0, x1, y1, fill;
188061b68a7SWarner Losh int nargs;
189061b68a7SWarner Losh
190061b68a7SWarner Losh nargs = lua_gettop(L);
191061b68a7SWarner Losh if (nargs != 5) {
192061b68a7SWarner Losh lua_pushnil(L);
193061b68a7SWarner Losh return 1;
194061b68a7SWarner Losh }
195061b68a7SWarner Losh
196061b68a7SWarner Losh x0 = luaL_checknumber(L, 1);
197061b68a7SWarner Losh y0 = luaL_checknumber(L, 2);
198061b68a7SWarner Losh x1 = luaL_checknumber(L, 3);
199061b68a7SWarner Losh y1 = luaL_checknumber(L, 4);
200061b68a7SWarner Losh fill = luaL_checknumber(L, 5);
201061b68a7SWarner Losh gfx_fb_drawrect(x0, y0, x1, y1, fill);
202061b68a7SWarner Losh return 0;
203061b68a7SWarner Losh }
204061b68a7SWarner Losh
205061b68a7SWarner Losh static int
lua_term_drawrect(lua_State * L)206061b68a7SWarner Losh lua_term_drawrect(lua_State *L)
207061b68a7SWarner Losh {
208061b68a7SWarner Losh uint32_t x0, y0, x1, y1;
209061b68a7SWarner Losh int nargs;
210061b68a7SWarner Losh
211061b68a7SWarner Losh nargs = lua_gettop(L);
212061b68a7SWarner Losh if (nargs != 4) {
213061b68a7SWarner Losh lua_pushnil(L);
214061b68a7SWarner Losh return 1;
215061b68a7SWarner Losh }
216061b68a7SWarner Losh
217061b68a7SWarner Losh x0 = luaL_checknumber(L, 1);
218061b68a7SWarner Losh y0 = luaL_checknumber(L, 2);
219061b68a7SWarner Losh x1 = luaL_checknumber(L, 3);
220061b68a7SWarner Losh y1 = luaL_checknumber(L, 4);
221061b68a7SWarner Losh gfx_term_drawrect(x0, y0, x1, y1);
222061b68a7SWarner Losh return 0;
223061b68a7SWarner Losh }
224061b68a7SWarner Losh
225061b68a7SWarner Losh #define REG_SIMPLE(n) { #n, lua_ ## n }
226061b68a7SWarner Losh static const struct luaL_Reg gfxlib[] = {
227061b68a7SWarner Losh REG_SIMPLE(fb_bezier),
228061b68a7SWarner Losh REG_SIMPLE(fb_drawrect),
229061b68a7SWarner Losh REG_SIMPLE(fb_line),
230061b68a7SWarner Losh REG_SIMPLE(fb_putimage),
231061b68a7SWarner Losh REG_SIMPLE(fb_setpixel),
232061b68a7SWarner Losh REG_SIMPLE(term_drawrect),
233061b68a7SWarner Losh REG_SIMPLE(term_putimage),
234061b68a7SWarner Losh { NULL, NULL },
235061b68a7SWarner Losh };
236061b68a7SWarner Losh
237061b68a7SWarner Losh int
luaopen_gfx(lua_State * L)238061b68a7SWarner Losh luaopen_gfx(lua_State *L)
239061b68a7SWarner Losh {
240061b68a7SWarner Losh luaL_newlib(L, gfxlib);
241061b68a7SWarner Losh return 1;
242061b68a7SWarner Losh }
24360e199d9SWarner Losh
24460e199d9SWarner Losh void
gfx_interp_ref(void)245*6faf55c8SWarner Losh gfx_interp_ref(void)
24660e199d9SWarner Losh {
24760e199d9SWarner Losh }
2480921a771SWarner Losh
2490921a771SWarner Losh static void
gfx_init_md(lua_State * L)2500921a771SWarner Losh gfx_init_md(lua_State *L)
2510921a771SWarner Losh {
2520921a771SWarner Losh luaL_requiref(L, "gfx", luaopen_gfx, 1);
2530921a771SWarner Losh lua_pop(L, 1); /* Remove lib */
2540921a771SWarner Losh
2550921a771SWarner Losh /*
2560921a771SWarner Losh * Add in the compatibility references in the loader table. Doing it with
2570921a771SWarner Losh * a pseudo-embedded script is easier than the raw calls.
2580921a771SWarner Losh */
2590921a771SWarner Losh if (luaL_dostring(L,
2600921a771SWarner Losh "loader.fb_bezier = gfx.fb_bezier\n"
2610921a771SWarner Losh "loader.fb_drawrect = gfx.fb_drawrect\n"
2620921a771SWarner Losh "loader.fb_line = gfx.fb_line\n"
2630921a771SWarner Losh "loader.fb_putimage = gfx.fb_putimage\n"
2640921a771SWarner Losh "loader.fb_setpixel = gfx.fb_setpixel\n"
2650921a771SWarner Losh "loader.term_drawrect = gfx.term_drawrect\n"
2660921a771SWarner Losh "loader.term_putimage = gfx.term_putimage") != 0) {
2670921a771SWarner Losh lua_pop(L, 1);
2680921a771SWarner Losh const char *errstr = lua_tostring(L, -1);
2690921a771SWarner Losh errstr = errstr == NULL ? "unknown" : errstr;
2700921a771SWarner Losh printf("Error adding compat loader bindings: %s.\n", errstr);
2710921a771SWarner Losh }
2720921a771SWarner Losh }
2730921a771SWarner Losh
2740921a771SWarner Losh LUA_COMPILE_SET(gfx_init_md);
275