1 /*
2 * Copyright (c) 2012-2014, Bruno Levy
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 * If you modify this software, you should include a notice giving the
30 * name of the person performing the modification, the date of modification,
31 * and the reason for such modification.
32 *
33 * Contact: Bruno Levy
34 *
35 * Bruno.Levy@inria.fr
36 * http://www.loria.fr/~levy
37 *
38 * ALICE Project
39 * LORIA, INRIA Lorraine,
40 * Campus Scientifique, BP 239
41 * 54506 VANDOEUVRE LES NANCY CEDEX
42 * FRANCE
43 *
44 */
45
46 #include <geogram_gfx/gui/simple_application.h>
47 #include <geogram_gfx/lua/lua_glup.h>
48 #include <geogram/lua/lua_io.h>
49 #include <geogram/basic/command_line.h>
50 #include <geogram/basic/file_system.h>
51 #include <algorithm>
52
53 extern "C" {
54 #include <geogram/third_party/lua/lua.h>
55 #include <geogram/third_party/lua/lauxlib.h>
56 #include <geogram/third_party/lua/lualib.h>
57 }
58
59 extern void register_embedded_lua_files(void);
60
61 namespace {
62
63 using namespace GEO;
64
65 /**
66 * \brief An application that demonstrates both
67 * GLUP primitives and glup_viewer application
68 * framework.
69 */
70 class GeoCodApplication : public SimpleApplication {
71 public:
72
73 /**
74 * \brief GeoCodApplication constructor.
75 */
GeoCodApplication()76 GeoCodApplication() : SimpleApplication("geocod") {
77 set_default_filename("hello.lua");
78 init_graphics_called_ = false;
79 use_text_editor_ = true;
80 text_editor_was_visible_ = false;
81 // Define the 3d region that we want to display
82 // (xmin, ymin, zmin, xmax, ymax, zmax)
83 set_region_of_interest(0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
84 register_embedded_lua_files();
85 exec_command("require(\"preamble\")");
86 console_->show_command_prompt();
87 }
88
89 /**
90 * \brief GeoCodApplication destructor.
91 */
~GeoCodApplication()92 ~GeoCodApplication() override {
93 }
94
95 /**
96 * \brief Displays and handles the GUI for object properties.
97 * \details Overloads Application::draw_object_properties().
98 */
draw_object_properties()99 void draw_object_properties() override {
100 if(!lua_error_occured_) {
101 exec_command("imgui.draw_object_properties()");
102 }
103 }
104
105 /**
106 * \brief Draws the scene according to currently set primitive and
107 * drawing modes.
108 */
draw_scene()109 void draw_scene() override {
110 if(text_editor_was_visible_ && !text_editor_visible_) {
111 run_program();
112 }
113 if(!lua_error_occured_) {
114 exec_command("GLUP.draw_scene()");
115 }
116 text_editor_was_visible_ = text_editor_visible_;
117 }
118
119 /**
120 * \brief Initializes graphics objects.
121 * \details This function overloads Application::init_graphics(). It
122 * is called as soon as the OpenGL context is ready for rendering. It
123 * is meant to initialize the graphic objects used by the application.
124 */
GL_initialize()125 void GL_initialize() override {
126 SimpleApplication::GL_initialize();
127 if(!lua_error_occured_) {
128 exec_command("GLUP.init_graphics()");
129 }
130 init_graphics_called_ = true;
131 }
132
embedded_files_menu(const std::string & prefix)133 void embedded_files_menu(const std::string& prefix) {
134 std::vector<std::string> embedded_files;
135 list_embedded_lua_files(embedded_files);
136 std::sort(embedded_files.begin(), embedded_files.end());
137 for(index_t i=0; i<embedded_files.size(); ++i) {
138 if(String::string_starts_with(
139 embedded_files[i],prefix) &&
140 ImGui::MenuItem(embedded_files[i].c_str())
141 ) {
142 const char* data;
143 get_embedded_lua_file(embedded_files[i].c_str(), &data);
144 text_editor_.load_data(data);
145 run_program();
146 current_file_ = "";
147 }
148 }
149 }
150
151
draw_fileops_menu()152 virtual void draw_fileops_menu() override {
153 if(ImGui::BeginMenu("New...")) {
154 if(ImGui::MenuItem("empty file")) {
155 text_editor_.clear();
156 current_file_ = "";
157 exec_command("require(\"preamble\")");
158 }
159 ImGui::Separator();
160 ImGui::MenuItem("From template...", nullptr, false, false);
161 embedded_files_menu("templates/");
162 ImGui::EndMenu();
163 }
164 if(ImGui::BeginMenu("Load example...")) {
165 embedded_files_menu("examples/");
166 ImGui::EndMenu();
167 }
168 if(ImGui::BeginMenu("Load game...")) {
169 embedded_files_menu("games/");
170 ImGui::EndMenu();
171 }
172 /*
173 if(ImGui::BeginMenu("Load Shift and Tab\'s adventure...")) {
174 embedded_files_menu("book/");
175 ImGui::EndMenu();
176 }
177 */
178 if(ImGui::BeginMenu("Load internal lib...")) {
179 ImGui::MenuItem("These files are those", nullptr, false, false);
180 ImGui::MenuItem(
181 "that are read by require(\"...\")",
182 nullptr, false, false
183 );
184 ImGui::MenuItem("You cannot modify them",
185 nullptr, false, false);
186 ImGui::MenuItem("(but you can take a look)",
187 nullptr, false, false);
188 ImGui::Separator();
189 embedded_files_menu("lib/");
190 ImGui::EndMenu();
191 }
192 if(ImGui::MenuItem(
193 "Run program",
194 phone_screen_ ? nullptr : "[F5]"
195 )) {
196 run_program();
197 }
198 }
199
run_program()200 void run_program() {
201 exec_command("require(\"preamble\")");
202 if(exec_command(text_editor_.text().c_str())) {
203 Logger::out("LUA") << "Program is OK." << std::endl;
204 } else {
205 adjust_lua_glup_state(lua_state_);
206 }
207 if(!lua_error_occured_ && init_graphics_called_) {
208 exec_command("GLUP.init_graphics()");
209 }
210 start_animation();
211 }
212
213 /**
214 * \brief Draws the application menus.
215 * \details This function overloads
216 * Application::draw_application_menus(). It can be used to create
217 * additional menus in the main menu bar.
218 */
draw_application_menus()219 void draw_application_menus() override {
220 if(!lua_error_occured_) {
221 exec_command("imgui.draw_application_menus()");
222 }
223 }
224
225 /**
226 * \copydoc Application::load()
227 */
load(const std::string & filename)228 bool load(const std::string& filename) override {
229 text_editor_.load(filename);
230 run_program();
231 current_file_ = filename;
232 return true;
233 }
234
235 /**
236 * \copydoc Application::save()
237 */
save(const std::string & filename)238 bool save(const std::string& filename) override {
239 text_editor_.save(filename);
240 current_file_ = filename;
241 return true;
242 }
243
244 /**
245 * \copydoc Application::supported_read_file_extensions()
246 */
supported_read_file_extensions()247 std::string supported_read_file_extensions() override {
248 return "lua";
249 }
250
251 /**
252 * \copydoc Application::supported_write_file_extensions()
253 */
supported_write_file_extensions()254 std::string supported_write_file_extensions() override {
255 return "lua";
256 }
257
258 /**
259 * \copydoc SimpleApplication::key_callback
260 */
key_callback(int key,int scancode,int action,int mods)261 void key_callback(
262 int key, int scancode, int action, int mods
263 ) override {
264 SimpleApplication::key_callback(key, scancode, action, mods);
265 const char* k_str = key_to_string(key);
266 // Get string from printable character
267 // (note: with GLFW, this does not interpret the key mapping,
268 // so Q and A are swapped on a French keyboard...)
269 if(*k_str == '\0') {
270 static char buff[2];
271 k_str = buff;
272 buff[0] = char(key);
273 buff[1] = '\0';
274 }
275 if(action == 1) {
276 on_key_pressed(k_str);
277 } else if(action == 0) {
278 on_key_released(k_str);
279 }
280 }
281
on_key_pressed(const char * c)282 bool on_key_pressed(const char* c) {
283 if(!strcmp(c,"F5")) {
284 run_program();
285 } else if(!strcmp(c,"F2") && current_file_ != "") {
286 if(save(current_file_)) {
287 Logger::out("I/O")
288 << "Saved " << current_file_ << std::endl;
289 }
290 } else {
291 exec_command(
292 (
293 std::string("imgui.on_key_pressed(\"") + c + "\")"
294 ).c_str()
295 );
296 }
297 return true;
298 }
299
on_key_released(const char * c)300 bool on_key_released(const char* c) {
301 exec_command(
302 (
303 std::string("imgui.on_key_released(\"") + c + "\")"
304 ).c_str()
305 );
306 return true;
307 }
308
309 protected:
draw_viewer_properties()310 void draw_viewer_properties() override {
311 if(ImGui::Button(
312 "run",
313 ImVec2(-ImGui::GetContentRegionAvail().x/2.0f,0.0f))
314 ) {
315 run_program();
316 }
317 ImGui::SameLine();
318 if(ImGui::Button("edit", ImVec2(-1.0f, 0.0f))) {
319 text_editor_visible_ = !text_editor_visible_;
320 }
321 ImGui::Separator();
322 SimpleApplication::draw_viewer_properties();
323 }
324
325 private:
326 bool init_graphics_called_;
327 bool text_editor_was_visible_;
328 };
329
330 }
331
main(int argc,char ** argv)332 int main(int argc, char** argv) {
333 GeoCodApplication app;
334 app.start(argc, argv);
335 return 0;
336 }
337