GCC Code Coverage Report


Directory: ./
File: lib/geogram_gfx/lua/lua_imgui.cpp
Date: 2026-09-07 02:28:19
Exec Total Coverage
Lines: 0 265 0.0%
Functions: 0 15 0.0%
Branches: 0 144 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #include <geogram_gfx/lua/lua_imgui.h>
41 #include <geogram_gfx/imgui_ext/imgui_ext.h>
42 #include <geogram_gfx/imgui_ext/icon_font.h>
43
44
45 #ifdef GEO_COMPILER_GCC_FAMILY
46 #pragma GCC diagnostic push
47 #pragma GCC diagnostic ignored "-Wfloat-conversion"
48 #endif
49
50 // Missing prototype in imoguizmo (slicences a warning)
51 namespace ImOGuizmo {
52 namespace internal {
53 struct ImVec3;
54 void lookAt(ImVec3 const& eye, ImVec3 const& at, ImVec3 const& up, float* viewMatrix);
55 }
56 }
57
58 #include <geogram_gfx/third_party/imoguizmo/imoguizmo.hpp>
59
60 #ifdef GEO_COMPILER_GCC_FAMILY
61 #pragma GCC diagnostic pop
62 #endif
63
64 #include <geogram/lua/lua_wrap.h>
65 #include <geogram/basic/string.h>
66 #include <geogram/basic/logger.h>
67 #include <map>
68
69 #include <geogram_gfx/third_party/imgui_lua_bindings_gomgen/luawrap_runtime.h>
70
71 extern void LoadImGuiBindings(lua_State* L);
72 extern void LoadImDrawListBindings(lua_State* L);
73
74
75 namespace {
76 using namespace GEO;
77
78
79 int wrapper_TextInput(lua_State* L) {
80
81 if(
82 lua_gettop(L) != 2 &&
83 lua_gettop(L) != 3
84 ) {
85 return luaL_error(
86 L, "'imgui.TextInput()' invalid number of arguments"
87 );
88 }
89
90 if(!lua_isstring(L,1)) {
91 return luaL_error(
92 L, "'imgui.TextInput()' argument 1 should be a string"
93 );
94 }
95
96 if(!lua_isstring(L,2)) {
97 return luaL_error(
98 L, "'imgui.TextInput()' argument 2 should be a string"
99 );
100 }
101
102 ImGuiInputTextFlags flags = 0;
103
104 if(lua_gettop(L) == 3) {
105 if(!lua_isnumber(L,3)) {
106 return luaL_error(
107 L, "'imgui.TextInput()' argument 3 should be a number"
108 );
109 }
110 flags = ImGuiInputTextFlags(lua_tonumber(L,3));
111 }
112
113 const char* label = lua_tostring(L,1);
114 const char* str = lua_tostring(L,2);
115 static char buff[geo_imgui_string_length];
116 strcpy(buff,str);
117 bool result = ImGui::InputText(
118 label, buff, geo_imgui_string_length, flags
119 );
120 lua_pushboolean(L,result);
121 lua_pushstring(L,buff);
122
123
124 return 2;
125 }
126
127
128 int wrapper_Combo(lua_State* L) {
129 if(lua_gettop(L) != 3) {
130 return luaL_error(
131 L, "'imgui.Combo()' invalid number of arguments"
132 );
133 }
134
135 if(!lua_isstring(L,1)) {
136 return luaL_error(
137 L, "'imgui.Combo()' argument should be a string"
138 );
139 }
140
141 if(!lua_isstring(L,2)) {
142 return luaL_error(
143 L, "'imgui.Combo()' argument should be a string"
144 );
145 }
146
147 if(!lua_isstring(L,3)) {
148 return luaL_error(
149 L, "'imgui.Combo()' argument should be a string"
150 );
151 }
152
153 const char* label = lua_tostring(L,1);
154 const char* current_item = lua_tostring(L,2);
155 const char* items = lua_tostring(L,3);
156
157 char* lua_items = (char*)alloca(strlen(items)+2);
158 strcpy(lua_items,items);
159 {
160 size_t n = strlen(lua_items);
161 lua_items[n] = ';';
162 lua_items[n+1] = '\0';
163 }
164
165 int lua_current_item=0;
166
167 const char* prev_item = lua_items;
168 int nb_items = 0;
169
170 char* p = lua_items;
171 while(*p != '\0') {
172 if(*p == ';') {
173 *p = '\0';
174 if(!strcmp(prev_item, current_item)) {
175 lua_current_item = nb_items;
176 }
177 prev_item = p+1;
178 ++nb_items;
179 }
180 ++p;
181 }
182 *p = '\0'; // Double '\0' to indicate end of item list to lua.
183
184 bool result = ImGui::Combo(label, &lua_current_item, lua_items);
185
186 current_item = lua_items;
187 while(lua_current_item > 0) {
188 while(*current_item) {
189 ++current_item;
190 }
191 ++current_item;
192 --lua_current_item;
193 }
194
195 lua_pushboolean(L, result);
196 lua_pushstring(L, current_item);
197
198 return 2;
199 }
200
201 int wrapper_ColorEdit3WithPalette(
202 lua_State* L
203 ) {
204 if(lua_gettop(L) != 4) {
205 return luaL_error(
206 L,
207 "'imgui.ColorEdit3WithPalette()' invalid number of arguments"
208 );
209 }
210
211 if(!lua_isstring(L,1)) {
212 return luaL_error(
213 L,
214 "'imgui.ColorEdit3WithPalette()' argument 1 should be a string"
215 );
216 }
217
218 if(!lua_isnumber(L,2)) {
219 return luaL_error(
220 L,
221 "'imgui.ColorEdit3WithPalette()' argument 2 should be a number"
222 );
223 }
224
225 if(!lua_isnumber(L,3)) {
226 return luaL_error(
227 L,
228 "'imgui.ColorEdit3WithPalette()' argument 3 should be a number"
229 );
230 }
231
232 if(!lua_isnumber(L,4)) {
233 return luaL_error(
234 L,
235 "'imgui.ColorEdit3WithPalette()' argument 4 should be a number"
236 );
237 }
238
239 const char* label = lua_tostring(L,1);
240
241 float rgb[3];
242 rgb[0] = float(lua_tonumber(L,2));
243 rgb[1] = float(lua_tonumber(L,3));
244 rgb[2] = float(lua_tonumber(L,4));
245
246 bool sel = ImGui::ColorEdit3WithPalette(
247 label, rgb
248 );
249
250 lua_pushboolean(L,sel);
251 lua_pushnumber(L,double(rgb[0]));
252 lua_pushnumber(L,double(rgb[1]));
253 lua_pushnumber(L,double(rgb[2]));
254
255 return 4;
256 }
257
258 int wrapper_ColorEdit4WithPalette(
259 lua_State* L
260 ) {
261 if(lua_gettop(L) != 5) {
262 return luaL_error(
263 L,
264 "'imgui.ColorEdit3WithPalette()' invalid number of arguments"
265 );
266 }
267
268 if(!lua_isstring(L,1)) {
269 return luaL_error(
270 L,
271 "'imgui.ColorEdit3WithPalette()' argument 1 should be a string"
272 );
273 }
274
275 if(!lua_isnumber(L,2)) {
276 return luaL_error(
277 L,
278 "'imgui.ColorEdit3WithPalette()' argument 2 should be a number"
279 );
280 }
281
282 if(!lua_isnumber(L,3)) {
283 return luaL_error(
284 L,
285 "'imgui.ColorEdit3WithPalette()' argument 3 should be a number"
286 );
287 }
288
289 if(!lua_isnumber(L,4)) {
290 return luaL_error(
291 L,
292 "'imgui.ColorEdit3WithPalette()' argument 4 should be a number"
293 );
294 }
295
296 if(!lua_isnumber(L,5)) {
297 return luaL_error(
298 L,
299 "'imgui.ColorEdit3WithPalette()' argument 5 should be a number"
300 );
301 }
302
303 const char* label = lua_tostring(L,1);
304
305 float rgb[4];
306 rgb[0] = float(lua_tonumber(L,2));
307 rgb[1] = float(lua_tonumber(L,3));
308 rgb[2] = float(lua_tonumber(L,4));
309 rgb[3] = float(lua_tonumber(L,5));
310
311 bool sel = ImGui::ColorEdit4WithPalette(
312 label, rgb
313 );
314
315 lua_pushboolean(L,sel);
316 lua_pushnumber(L,double(rgb[0]));
317 lua_pushnumber(L,double(rgb[1]));
318 lua_pushnumber(L,double(rgb[2]));
319 lua_pushnumber(L,double(rgb[3]));
320
321 return 5;
322 }
323
324
325 int wrapper_OpenFileDialog(
326 lua_State* L
327 ) {
328 if(lua_gettop(L) != 4) {
329 return luaL_error(
330 L, "'imgui.OpenFileDialog()' invalid number of arguments"
331 );
332 }
333
334 if(!lua_isstring(L,1)) {
335 return luaL_error(
336 L, "'imgui.OpenFileDialog()' argument 1 should be a string"
337 );
338 }
339
340 if(!lua_isstring(L,2)) {
341 return luaL_error(
342 L, "'imgui.OpenFileDialog()' argument 2 should be a string"
343 );
344 }
345
346 if(!lua_isstring(L,3)) {
347 return luaL_error(
348 L, "'imgui.OpenFileDialog()' argument 3 should be a string"
349 );
350 }
351
352 if(!lua_isnumber(L,4)) {
353 return luaL_error(
354 L, "'imgui.OpenFileDialog()' argument 4 should be a number"
355 );
356 }
357
358 const char* label = lua_tostring(L,1);
359 const char* extensions = lua_tostring(L,2);
360 const char* filename = lua_tostring(L,3);
361 ImGuiExtFileDialogFlags flags =
362 ImGuiExtFileDialogFlags(lua_tonumber(L,4));
363
364 ImGui::OpenFileDialog(label, extensions, filename, flags);
365
366 return 0;
367 }
368
369 int wrapper_FileDialog(
370 lua_State* L
371 ) {
372 if(lua_gettop(L) != 2) {
373 return luaL_error(
374 L, "'imgui.FileDialog()' invalid number of arguments"
375 );
376 }
377
378 if(!lua_isstring(L,1)) {
379 return luaL_error(
380 L, "'imgui.OpenFileDialog()' argument 1 should be a string"
381 );
382 }
383
384 if(!lua_isstring(L,2)) {
385 return luaL_error(
386 L, "'imgui.OpenFileDialog()' argument 2 should be a string"
387 );
388 }
389
390 const char* label = lua_tostring(L,1);
391 char filename[geo_imgui_string_length];
392
393 const char* filename_in = lua_tostring(L,2);
394 if(filename_in != nullptr) {
395 if(strlen(filename_in) > geo_imgui_string_length + 1) {
396 Logger::err("ImGui") << "Max file name length exceeded"
397 << std::endl;
398 return false;
399 }
400 strcpy(filename, filename_in);
401 } else {
402 filename[0] = '\0';
403 }
404
405 bool result =
406 ImGui::FileDialog(label, filename, geo_imgui_string_length);
407
408 lua_pushboolean(L,result);
409 lua_pushstring(L, result ? filename : filename_in);
410
411 return 2;
412 }
413
414 int wrapper_PushFont(lua_State* L) {
415 if(lua_gettop(L) != 1) {
416 return luaL_error(
417 L, "'imgui.PushFont()' invalid number of arguments"
418 );
419 }
420 if(!lua_isinteger(L,1)) {
421 return luaL_error(
422 L, "'imgui.PushFont()' argument is not an integer"
423 );
424 }
425 int idx = int(lua_tointeger(L,1));
426 if(idx < 0 || idx >= ImGui::GetIO().Fonts->Fonts.size()) {
427 return luaL_error(
428 L, "'imgui.PushFont()' invalid font index"
429 );
430 }
431 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[idx]);
432 return 0;
433 }
434
435 int wrapper_font_icon(lua_State* L) {
436 if(lua_gettop(L) != 1) {
437 return luaL_error(
438 L, "'imgui.font_icon()' invalid number of arguments"
439 );
440 }
441 if(!lua_isstring(L,1)) {
442 return luaL_error(
443 L, "'imgui.font_icon()' argument is not a string"
444 );
445 }
446 const char* K = lua_tostring(L,1);
447 wchar_t result[2];
448 result[0] = icon_wchar(K);
449 result[1] = '\0';
450 std::string result_str = String::wchar_to_UTF8(result);
451 lua_pushstring(L, result_str.c_str());
452 return 1;
453 }
454
455 int wrapper_SimpleButton(lua_State* L) {
456 if(lua_gettop(L) != 1) {
457 return luaL_error(
458 L, "'imgui.SimpleButton()' invalid number of arguments"
459 );
460 }
461 if(!lua_isstring(L,1)) {
462 return luaL_error(
463 L, "'imgui.SimpleButton()' argument is not a string"
464 );
465 }
466 const char* K = lua_tostring(L,1);
467 lua_pushboolean(L,ImGui::SimpleButton(K));
468 return 1;
469 }
470
471 int wrapper_SimpleButton2(lua_State* L) {
472 if(lua_gettop(L) != 3) {
473 return luaL_error(
474 L, "'imgui.SimpleButton2()' invalid number of arguments"
475 );
476 }
477 if(!lua_isstring(L,1)) {
478 return luaL_error(
479 L, "'imgui.SimpleButton2()' argument is not a string"
480 );
481 }
482 if(!lua_isnumber(L,2)) {
483 return luaL_error(
484 L, "'imgui.SimpleButton2()' argument is not a number"
485 );
486 }
487 if(!lua_isnumber(L,3)) {
488 return luaL_error(
489 L, "'imgui.SimpleButton2()' argument is not a number"
490 );
491 }
492 const char* K = lua_tostring(L,1);
493 lua_pushboolean(
494 L,
495 ImGui::SimpleButton(
496 K,
497 ImVec2(float(lua_tonumber(L,2)), float(lua_tonumber(L,3))))
498 );
499 return 1;
500 }
501
502 int wrapper_DrawGizmo(lua_State* L) {
503 if(lua_gettop(L) != 3) {
504 return luaL_error(
505 L, "'ImOGuizmo.DrawGizmo()' invalid number of arguments"
506 );
507 }
508 Matrix<4,float> vm;
509 Matrix<4,float> pm;
510 if(!lua_tomat(L,1,vm)) {
511 return luaL_error(
512 L, "'ImOGuizmo.DrawGizmo()' arg 1 is not a matrix"
513 );
514 }
515 if(!lua_tomat(L,2,pm)) {
516 return luaL_error(
517 L, "'ImOGuizmo.DrawGizmo()' arg 2 is not a matrix"
518 );
519 }
520 if(!lua_isnumber(L,3)) {
521 return luaL_error(
522 L, "'imOGuizmo.DrawGizmo()' arg 3 is not a number"
523 );
524 }
525 float distance = float(lua_tonumber(L,3));
526 bool changed = ImOGuizmo::DrawGizmo(vm.data(), pm.data(), distance);
527 lua_push(L,changed);
528 lua_push(L,vm);
529 return 2;
530 }
531
532 int wrapper_IO_DisplayFramebufferScale(lua_State* L) {
533 if(lua_gettop(L) != 0) {
534 return luaL_error(
535 L, "'IO_DisplayFramebufferScale' invalid number of arguments"
536 );
537 }
538 lua_pushnumber(L,lua_Number(ImGui::GetIO().DisplayFramebufferScale.x));
539 lua_pushnumber(L,lua_Number(ImGui::GetIO().DisplayFramebufferScale.y));
540 return 2;
541 }
542 }
543
544 #define DECLARE_IMGUI_CONSTANT(C) \
545 lua_pushinteger(L,C); \
546 lua_setglobal(L,#C)
547
548
549 // Overloads (that gomgen cannot generate yet)
550 namespace ImGui_lua_wrappers {
551 using namespace LuaWrap;
552
553 static int PushStyleVar_2(lua_State* L) {
554 static const char* proto =
555 "void ImGui::PushStyleVar_2(ImGuiStyleVar idx, ImVec2 val)";
556 Arg<int,lua_Integer> idx(L,1);
557 Arg<ImVec2> val(L,2);
558 LUAWRAP_CHECK_ARGS(idx, val);
559 ImGui::PushStyleVar(idx.value, val.value);
560 return 0;
561 }
562
563 static int PushStyleColor_2(lua_State* L) {
564 static const char* proto =
565 "void ImGui::PushStyleColor_2(ImGuiCol idx, ImVec4 col)";
566 Arg<int,lua_Integer> idx(L,1);
567 Arg<ImVec4> col(L,2);
568 LUAWRAP_CHECK_ARGS(idx, col);
569 ImGui::PushStyleColor(idx.value, col.value);
570 return 0;
571 }
572 }
573
574 void init_lua_imgui(lua_State* L) {
575 LoadImGuiBindings(L);
576 LoadImDrawListBindings(L);
577
578 DECLARE_IMGUI_CONSTANT(ImGuiExtFileDialogFlags_Load);
579 DECLARE_IMGUI_CONSTANT(ImGuiExtFileDialogFlags_Save);
580
581 lua_getglobal(L, "imgui");
582
583 lua_pushliteral(L,"TextInput");
584 lua_pushcfunction(L,wrapper_TextInput);
585 lua_settable(L,-3);
586
587 lua_pushliteral(L,"Combo");
588 lua_pushcfunction(L,wrapper_Combo);
589 lua_settable(L,-3);
590
591 lua_pushliteral(L,"ColorEdit3WithPalette");
592 lua_pushcfunction(L,wrapper_ColorEdit3WithPalette);
593 lua_settable(L,-3);
594
595 lua_pushliteral(L,"ColorEdit4WithPalette");
596 lua_pushcfunction(L,wrapper_ColorEdit4WithPalette);
597 lua_settable(L,-3);
598
599 lua_pushliteral(L,"OpenFileDialog");
600 lua_pushcfunction(L,wrapper_OpenFileDialog);
601 lua_settable(L,-3);
602
603 lua_pushliteral(L,"FileDialog");
604 lua_pushcfunction(L,wrapper_FileDialog);
605 lua_settable(L,-3);
606
607 lua_pushliteral(L,"PushFont");
608 lua_pushcfunction(L,wrapper_PushFont);
609 lua_settable(L,-3);
610
611 lua_pushliteral(L,"font_icon");
612 lua_pushcfunction(L,wrapper_font_icon);
613 lua_settable(L,-3);
614
615 lua_pushliteral(L,"SimpleButton");
616 lua_pushcfunction(L,wrapper_SimpleButton);
617 lua_settable(L,-3);
618
619 lua_pushliteral(L,"SimpleButton2");
620 lua_pushcfunction(L,wrapper_SimpleButton2);
621 lua_settable(L,-3);
622
623 /*****************************************************************/
624
625 lua_pushliteral(L,"IO_DisplayFramebufferScale");
626 lua_pushcfunction(L,wrapper_IO_DisplayFramebufferScale);
627 lua_settable(L,-3);
628
629 /*****************************************************************/
630
631 // Overloads that could not be generated by gomgen
632 using namespace ImGui_lua_wrappers;
633 LUAWRAP_DECLARE_FUNCTION(L,PushStyleVar_2);
634 LUAWRAP_DECLARE_FUNCTION(L,PushStyleColor_2);
635
636 /*****************************************************************/
637
638 lua_pop(L,1);
639
640 lua_newtable(L);
641 lua_bindwrapper(L,ImOGuizmo::BeginFrame);
642 lua_bindwrapper(L,ImOGuizmo::SetRect);
643
644 lua_pushliteral(L,"DrawGizmo");
645 lua_pushcfunction(L,wrapper_DrawGizmo);
646 lua_settable(L,-3);
647 lua_setglobal(L,"ImOGuizmo");
648 }
649