diff --git a/CMakeLists.txt b/CMakeLists.txt index f9bda6c3..8ef9bcf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,7 @@ if (NOT WINDOWS) add_compile_definitions(LUA_USE_POSIX) endif() -file(GLOB LUA_SRC "include/vendored/lua/src/*.c") +file(GLOB LUA_SRC "include/vendored/lua/src/*.cpp") include_directories(include/vendored/lua/src) add_library(Lua STATIC ${LUA_SRC}) diff --git a/include/camera.h b/include/camera.h index 03b4f571..c389d67a 100644 --- a/include/camera.h +++ b/include/camera.h @@ -82,6 +82,7 @@ class Camera pv = projection*view; invPv = glm::inverse(pv); + updated = true; } /** @@ -317,6 +318,8 @@ class Camera */ inline int lua_getCameraFieldOfView(lua_State * lua); + bool updated = false; + private: uint16_t resX; @@ -345,6 +348,7 @@ class Camera invView = glm::inverse(view); pv = projection*view; invPv = glm::inverse(pv); + updated = true; } }; diff --git a/include/cameraWindow.h b/include/cameraWindow.h index 953591cb..b1ebaefb 100644 --- a/include/cameraWindow.h +++ b/include/cameraWindow.h @@ -26,21 +26,6 @@ class CameraWindow { public: - /** - * @brief If the Camera or Atoms require updates. - * - */ - struct CameraUpdates - { - CameraUpdates() - : cameraMoved(false), - atomsMoved(false) - {} - - bool cameraMoved; - bool atomsMoved; - }; - CameraWindow() {} /** @@ -146,43 +131,42 @@ class CameraWindow * * @param camera the Camera to update. * @param atoms the Atoms to update. + * @param atomsMoved signal if atoms have been modified. * @param options the options to use for actions. * @param dr the length unit. * @param dtheta the rotation unit. * @param dphi the incline unit. - * @return CameraUpdates Whether the Camera or Atoms were updated. */ - CameraUpdates applyQueueActions + void applyQueueActions ( Camera & camera, std::vector & atoms, + bool & atomsMoved, const CommandLine & options, const float & dr, const float & dtheta, const float & dphi ) { - CameraUpdates moved; - if (zoomQueue != 0) { camera.zoom(dr*options.cameraZoomSpeed.value*zoomQueue); zoomQueue = 0; - moved.cameraMoved = true; + atomsMoved = true; } if (rotateQueue != 0) { camera.rotate(dtheta*options.cameraRotateSpeed.value*rotateQueue); rotateQueue = 0; - moved.cameraMoved = true; + atomsMoved = true; } if (inclineQueue != 0) { camera.incline(dphi*options.cameraInclineSpeed.value*inclineQueue); inclineQueue = 0; - moved.cameraMoved = true; + atomsMoved = true; } if (resetCamera) @@ -190,8 +174,7 @@ class CameraWindow if (!options.noCentering.value) { center(atoms); } if (options.focus.value < atoms.size()) { centerOn(atoms, options.focus.value); } camera.reset(atoms); - moved.atomsMoved = true; - moved.cameraMoved = true; + atomsMoved = true; resetCamera = false; } @@ -199,24 +182,22 @@ class CameraWindow { translate(atoms, {dr*options.cameraPanSpeed.value*panxQueue, 0.0, 0.0}); panxQueue = 0; - moved.atomsMoved = true; + atomsMoved = true; } if (panyQueue != 0) { translate(atoms, {0.0, dr*options.cameraPanSpeed.value*panyQueue, 0.0}); panyQueue = 0; - moved.atomsMoved = true; + atomsMoved = true; } if (panzQueue != 0) { translate(atoms, {0.0, 0.0, dr*options.cameraPanSpeed.value*panzQueue}); panzQueue = 0; - moved.atomsMoved = true; + atomsMoved = true; } - - return moved; } private: diff --git a/include/console.h b/include/console.h index 6e89eb01..b6382dcf 100644 --- a/include/console.h +++ b/include/console.h @@ -6,8 +6,7 @@ #include #include #include - -#include +#include #include #include @@ -178,18 +177,16 @@ class Console public: /** - * @brief Construct a new Console with a jLog::Log. + * @brief Construct a new Console. * - * @param l jLog::Log outputting Lua's messages. */ Console ( - jLog::Log & l, VisualisationState * visualisationState, CommandLine * options, Camera * camera ) - : lastCommandOrProgram(""), lastStatus(false), log(l) + : lastCommandOrProgram(""), lastStatus(false) { lua = luaL_newstate(); luaL_openlibs(lua); @@ -199,6 +196,17 @@ class Console extraSpace.camera = camera; extraSpace.exit = &exit; *static_cast(lua_getextraspace(lua)) = &extraSpace; + + const char * init = R"( + function use(module) + for k,v in pairs(module) do + if not _G[k] then + _G[k] = module[k] + end + end + end + use(sfoav))"; + runString(init); } ~Console(){ lua_close(lua); } @@ -216,11 +224,7 @@ class Console { lastCommandOrProgram = file; lastStatus = luaL_loadfile(lua, file.c_str()); - int epos = lua_gettop(lua); - lua_pushcfunction(lua, traceback); - lua_insert(lua, epos); - lastStatus = lastStatus || lua_pcall(lua, 0, LUA_MULTRET, epos); - lua_remove(lua, epos); + lastStatus = lastStatus || lua_pcall(lua, 0, LUA_MULTRET, 0); return handleErrors(); } return false; @@ -236,13 +240,31 @@ class Console bool runString(std::string program) { if (luaIsOk()) - { lastCommandOrProgram = program; + { + lastCommandOrProgram = program; lastStatus = luaL_dostring(lua,program.c_str()); return handleErrors(); } return false; } + /** + * @brief Attempt to run a Lua script from std::string. + * + * @param file Lua script. + * @return true Error occured. + * @return false OK. + */ + bool runString(const char * program) + { + if (luaIsOk()) + { lastCommandOrProgram = std::string(program); + lastStatus = luaL_dostring(lua,program); + return handleErrors(); + } + return false; + } + bool luaIsOk(){ return lua_status(lua) == LUA_OK ? true : false; } /** @@ -310,27 +332,12 @@ class Console bool lastStatus; bool exit = false; - jLog::Log & log; - - static int traceback(lua_State * lua) { - if (lua_isstring(lua, -1)) - { - stackTrace = lua_tostring(lua, -1); - lua_pop(lua, 1); - } - luaL_traceback(lua, lua, NULL, 1); - stackTrace += std::string("\n") + lua_tostring(lua, -1); - lua_pop(lua, 1); - return 0; - } - bool handleErrors() { if (lastStatus) { - std::string msg = "Exited with error running "+lastCommandOrProgram+"\n"; - msg += stackTrace; - jLog::ERR(jLog::ERRORCODE::LUA_ERROR, msg) >> log; + if (lua_isstring(lua, -1)) { std::cerr << lua_tostring(lua, -1) << "\n"; } + else { std::cerr << "Exited with error running "+lastCommandOrProgram+"\n"; } return true; } else diff --git a/include/consoleWindow.h b/include/consoleWindow.h new file mode 100644 index 00000000..5b5ebb5e --- /dev/null +++ b/include/consoleWindow.h @@ -0,0 +1,407 @@ +#ifndef CONSOLEWINDOW_H +#define CONSOLEWINDOW_H + +#include +#include +#include + +#ifdef WINDOWS +#include +#endif + +#ifdef MACOS +#include +#endif + +#include +#include +#include + +#include +#include + +/** + * @brief A window for Console (from Imgui example.) + * + */ +struct ConsoleWindow +{ + char InputBuf[256]; + ImVector Items; + ImVector Commands; + ImVector History; + int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. + ImGuiTextFilter Filter; + bool AutoScroll; + bool ScrollToBottom; + bool focussed; + const unsigned logLineSize = 2048; + + std::streambuf * ocout; + std::streambuf * ocerr; + + std::stringstream out; + std::stringstream err; + + /** + * @brief The text banner. + * + */ + const char * banner = R"( ________ ________ ________ ________ ___ ___ +|\ ____\|\ _____\\ __ \|\ __ \|\ \ / /| +\ \ \___|\ \ \__/\ \ \|\ \ \ \|\ \ \ \ / / / + \ \_____ \ \ __\\ \ \\\ \ \ __ \ \ \/ / / + \|____|\ \ \ \_| \ \ \\\ \ \ \ \ \ \ / / + ____\_\ \ \__\ \ \_______\ \__\ \__\ \__/ / + |\_________\|__| \|_______|\|__|\|__|\|__|/ + \|_________| SimpleFastOpenAtomicVisualiser + +Copyright (C) 2025 Jerboa +SimpleFastOpenAtomicVisualiser comes with ABSOLUTELY NO WARRANTY; for details run GPL. +This is free software, and you are welcome to redistribute it under certain conditions.)"; + + /** + * @brief Construct a new ConsoleWindow + * @remark redirects cout and cerr to the console window. + */ + ConsoleWindow() + { + ocout = std::cout.rdbuf(out.rdbuf()); + ocerr = std::cerr.rdbuf(err.rdbuf()); + + clearLog(); + memset(InputBuf, 0, sizeof(InputBuf)); + HistoryPos = -1; + + Commands.push_back("HELP"); + Commands.push_back("HISTORY"); + Commands.push_back("CLEAR"); + AutoScroll = true; + ScrollToBottom = false; + addLog(std::string(banner)); + } + ~ConsoleWindow() + { + clearLog(); + for (int i = 0; i < History.Size; i++) + { + ImGui::MemFree(History[i]); + } + std::cout.rdbuf(ocout); + std::cerr.rdbuf(ocerr); + } + + // Portable helpers + static int Stricmp(const char* s1, const char* s2) { int d; while ((d = std::toupper(*s2) - std::toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } + static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = std::toupper(*s2) - std::toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; } + static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = ImGui::MemAlloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } + static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } + + /** + * @brief Clear the ConsoleWindow's log. + * + */ + void clearLog() + { + for (int i = 0; i < Items.Size; i++) + { + ImGui::MemFree(Items[i]); + } + Items.clear(); + } + + /** + * @brief Add a const char * to the log. + */ + void addLog(const char* fmt, ...) IM_FMTARGS(2) + { + char buf[logLineSize]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf)-1] = 0; + va_end(args); + Items.push_back(Strdup(buf)); + } + + /** + * @brief Add a string to the log. + * @param s the string to add. + */ + void addLog(std::string s) + { + if (s.size() <= logLineSize) { addLog("%s", s.c_str()); } + else + { + for (unsigned i = 0; i < s.size(); i += logLineSize) + { + std::cout << s.substr(i, logLineSize).size() << "\n"; + addLog("%s", s.substr(i, logLineSize).c_str()); + } + } + } + + /** + * @brief Draw the console window. + * + * @param title the name of the window. + * @param console the Console to execute commands with. + */ + void draw(const char* title, Console & console) + { + std::string line; + + while (std::getline(out,line)) { addLog(line); } + out.clear(); + + while (std::getline(err,line)) { addLog("[ERROR] "+line); } + err.clear(); + + ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin(title)) + { + ImGui::End(); + return; + } + + focussed = ImGui::IsWindowFocused(); + + ImGui::TextWrapped("Enter 'HELP' for help."); + + if (ImGui::SmallButton("Clear")) { clearLog(); } + + ImGui::Separator(); + + // Reserve enough left-over height for 1 separator + 1 input text + const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar)) + { + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Selectable("Clear")) { clearLog(); } + ImGui::EndPopup(); + } + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing + + for (const char* item : Items) + { + if (!Filter.PassFilter(item)) + { + continue; + } + // Normally you would store more information in your item than just a string. + // (e.g. make Items[] an array of structure, store color/type etc.) + ImVec4 color; + bool has_color = false; + if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } + else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } + if (has_color) { ImGui::PushStyleColor(ImGuiCol_Text, color); } + ImGui::TextWrapped("%s", item); + if (has_color) { ImGui::PopStyleColor(); } + } + + // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame. + // Using a scrollbar or mouse-wheel will take away from the bottom edge. + if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) { ImGui::SetScrollHereY(1.0f); } + ScrollToBottom = false; + + ImGui::PopStyleVar(); + } + ImGui::EndChild(); + ImGui::Separator(); + + // Command-line + bool reclaim_focus = false; + ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; + if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) + { + char* s = InputBuf; + Strtrim(s); + if (s[0]) { execCommand(s, console); } + strcpy(s, ""); + reclaim_focus = true; + } + + // Auto-focus on window apparition + ImGui::SetItemDefaultFocus(); + // Auto focus previous widget + if (reclaim_focus) { ImGui::SetKeyboardFocusHere(-1); } + + ImGui::End(); + } + + /** + * @brief Execute a console command. + * + * @param command_line the command. + * @param console the Console to execute with. + */ + void execCommand(const char* command_line, Console & console) + { + addLog("# %s\n", command_line); + + // Insert into history. First find match and delete it so it can be pushed to the back. + // This isn't trying to be smart or optimal. + HistoryPos = -1; + for (int i = History.Size - 1; i >= 0; i--) + { + if (Stricmp(History[i], command_line) == 0) + { + ImGui::MemFree(History[i]); + History.erase(History.begin() + i); + break; + } + } + History.push_back(Strdup(command_line)); + + // Process command + if (Stricmp(command_line, "CLEAR") == 0) + { + clearLog(); + } + else if (Stricmp(command_line, "HELP") == 0) + { + addLog("Commands:"); + for (int i = 0; i < Commands.Size; i++) + { + addLog("- %s", Commands[i]); + } + } + else if (Stricmp(command_line, "HISTORY") == 0) + { + int first = History.Size - 10; + for (int i = first > 0 ? first : 0; i < History.Size; i++) + { + addLog("%3d: %s\n", i, History[i]); + } + } + else + { + console.runString(command_line); + } + + // On command input, we scroll to bottom even if AutoScroll==false + ScrollToBottom = true; + } + + // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks + static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) + { + ConsoleWindow* console = (ConsoleWindow*)data->UserData; + return console->textEditCallback(data); + } + + int textEditCallback(ImGuiInputTextCallbackData* data) + { + switch (data->EventFlag) + { + case ImGuiInputTextFlags_CallbackCompletion: + { + // Example of TEXT COMPLETION + + // Locate beginning of current word + const char* word_end = data->Buf + data->CursorPos; + const char* word_start = word_end; + while (word_start > data->Buf) + { + const char c = word_start[-1]; + if (c == ' ' || c == '\t' || c == ',' || c == ';') { break; } + word_start--; + } + + // Build a list of candidates + ImVector candidates; + for (int i = 0; i < Commands.Size; i++) + { + if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) + { + candidates.push_back(Commands[i]); + } + } + if (candidates.Size == 0) + { + // No match + addLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); + } + else if (candidates.Size == 1) + { + // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); + data->InsertChars(data->CursorPos, candidates[0]); + data->InsertChars(data->CursorPos, " "); + } + else + { + // Multiple matches. Complete as much as we can.. + // So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + int match_len = (int)(word_end - word_start); + for (;;) + { + int c = 0; + bool all_candidates_matches = true; + for (int i = 0; i < candidates.Size && all_candidates_matches; i++) + { + if (i == 0) + { + c = std::toupper(candidates[i][match_len]); + } + else if (c == 0 || c != std::toupper(candidates[i][match_len])) + { + all_candidates_matches = false; + } + } + if (!all_candidates_matches) { break; } + match_len++; + } + + if (match_len > 0) + { + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); + data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); + } + + // List matches + addLog("Possible matches:\n"); + for (int i = 0; i < candidates.Size; i++) + { + addLog("- %s\n", candidates[i]); + } + } + + break; + } + case ImGuiInputTextFlags_CallbackHistory: + { + // Example of HISTORY + const int prev_history_pos = HistoryPos; + if (data->EventKey == ImGuiKey_UpArrow) + { + if (HistoryPos == -1) { HistoryPos = History.Size - 1; } + else if (HistoryPos > 0) { HistoryPos--; } + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + if (HistoryPos != -1) + { + if (++HistoryPos >= History.Size) + { + HistoryPos = -1; + } + } + } + + // A better implementation would preserve the data on the current input line along with cursor position. + if (prev_history_pos != HistoryPos) + { + const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, history_str); + } + } + } + return 0; + } +}; + +#endif /* CONSOLEWINDOW_H */ diff --git a/include/lua.h b/include/lua.h index ca83938d..6ff4f350 100644 --- a/include/lua.h +++ b/include/lua.h @@ -7,12 +7,9 @@ #include #include -extern "C" -{ - #include - #include - #include -} +#include +#include +#include /** * @brief Get the a Lua table of doubles. diff --git a/include/luaBindings/visualisationState/atoms.h b/include/luaBindings/visualisationState/atoms.h index b9408c85..862a94fa 100644 --- a/include/luaBindings/visualisationState/atoms.h +++ b/include/luaBindings/visualisationState/atoms.h @@ -56,6 +56,7 @@ inline int VisualisationState::lua_setAtomColour(lua_State * lua) a = std::clamp(float(lua_a.n), 0.0f, 1.0f); } atomColourOverrides[index] = glm::vec4(r, g, b, a); + elementsUpdated = true; return 0; } diff --git a/include/luaBindings/visualisationState/bonds.h b/include/luaBindings/visualisationState/bonds.h index e16eb4bd..462da244 100644 --- a/include/luaBindings/visualisationState/bonds.h +++ b/include/luaBindings/visualisationState/bonds.h @@ -40,6 +40,7 @@ inline int VisualisationState::lua_bond(lua_State * lua) { bonds[j].erase(i); } + elementsUpdated = true; return 0; } @@ -88,6 +89,7 @@ inline int VisualisationState::lua_unbond(lua_State * lua) { bonds[j].erase(i); } + elementsUpdated = true; return 0; } diff --git a/include/main.h b/include/main.h index c808a60f..b7a5c840 100644 --- a/include/main.h +++ b/include/main.h @@ -16,8 +16,6 @@ #include -#include - #include #include #include @@ -146,7 +144,7 @@ Theme lightTheme() * @return true if the camera moved. * @return false if the camera did not move. */ -bool cameraControls +void cameraControls ( jGL::DesktopDisplay & display, Camera & camera, @@ -155,38 +153,30 @@ bool cameraControls float inclineSpeed ) { - bool moved = false; if (display.keyHasAnyEvents(GLFW_KEY_W, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { camera.zoom(-dr*zoomSpeed); - moved = true; } if (display.keyHasAnyEvents(GLFW_KEY_S, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { camera.zoom(dr*zoomSpeed); - moved = true; } if (display.keyHasAnyEvents(GLFW_KEY_Q, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { camera.incline(dtheta*inclineSpeed); - moved = true; } if (display.keyHasAnyEvents(GLFW_KEY_E, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { camera.incline(-dtheta*inclineSpeed); - moved = true; } if (display.keyHasAnyEvents(GLFW_KEY_A, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { camera.rotate(-dphi*rotateSpeed); - moved = true; } if (display.keyHasAnyEvents(GLFW_KEY_D, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { camera.rotate(dphi*rotateSpeed); - moved = true; } - return moved; } /** diff --git a/include/structure.h b/include/structure.h index 9067c3b4..793eb2c9 100644 --- a/include/structure.h +++ b/include/structure.h @@ -180,6 +180,8 @@ class Structure */ std::string getPath() { return path.string(); } + bool updated = false; + protected: std::filesystem::path path; diff --git a/include/vendored/lua/src/lapi.c b/include/vendored/lua/src/lapi.cpp similarity index 100% rename from include/vendored/lua/src/lapi.c rename to include/vendored/lua/src/lapi.cpp diff --git a/include/vendored/lua/src/lauxlib.c b/include/vendored/lua/src/lauxlib.cpp similarity index 100% rename from include/vendored/lua/src/lauxlib.c rename to include/vendored/lua/src/lauxlib.cpp diff --git a/include/vendored/lua/src/lauxlib.h b/include/vendored/lua/src/lauxlib.h index 5b977e2a..7fa1a12d 100644 --- a/include/vendored/lua/src/lauxlib.h +++ b/include/vendored/lua/src/lauxlib.h @@ -11,6 +11,7 @@ #include #include +#include #include "luaconf.h" #include "lua.h" @@ -257,18 +258,18 @@ typedef struct luaL_Stream { /* print a string */ #if !defined(lua_writestring) -#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#define lua_writestring(s,l) (std::cout << s) #endif /* print a newline and flush the output */ #if !defined(lua_writeline) -#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) +#define lua_writeline() (std::cout << "\n") #endif /* print an error message */ #if !defined(lua_writestringerror) #define lua_writestringerror(s,p) \ - (fprintf(stderr, (s), (p)), fflush(stderr)) + (std::cout << s << p << "\n") #endif /* }================================================================== */ diff --git a/include/vendored/lua/src/lbaselib.c b/include/vendored/lua/src/lbaselib.cpp similarity index 96% rename from include/vendored/lua/src/lbaselib.c rename to include/vendored/lua/src/lbaselib.cpp index 98d94978..9b5d8c91 100644 --- a/include/vendored/lua/src/lbaselib.c +++ b/include/vendored/lua/src/lbaselib.cpp @@ -20,35 +20,15 @@ #include "lauxlib.h" #include "lualib.h" -#ifdef ANDROID - #include -#endif - - -#if !defined(ANDROID) && !defined(WINDOWS) - const char * LUA_PRINT_ENTRY = "\033[1;34m[LUA] \033[0m\0"; - const size_t LUA_ENTRY_LENGTH = 23; -#else -// it is more complicated than this, LUA interprets some of -// the escapes differently - const char * LUA_PRINT_ENTRY = "[LUA] \0"; - const size_t LUA_ENTRY_LENGTH = 6; -#endif - - static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; - lua_writestring(LUA_PRINT_ENTRY,LUA_ENTRY_LENGTH); for (i = 1; i <= n; i++) { /* for each argument */ size_t l; const char *s = luaL_tolstring(L, i, &l); /* convert it to string */ if (i > 1) /* not the first element? */ lua_writestring("\t", 1); /* add a tab before it */ lua_writestring(s, l); /* print it */ - #if defined(ANDROID) - __android_log_print(ANDROID_LOG_INFO,"LUA","%s",s); - #endif lua_pop(L, 1); /* pop result */ } lua_writeline(); diff --git a/include/vendored/lua/src/lcode.c b/include/vendored/lua/src/lcode.cpp similarity index 100% rename from include/vendored/lua/src/lcode.c rename to include/vendored/lua/src/lcode.cpp diff --git a/include/vendored/lua/src/lcorolib.c b/include/vendored/lua/src/lcorolib.cpp similarity index 100% rename from include/vendored/lua/src/lcorolib.c rename to include/vendored/lua/src/lcorolib.cpp diff --git a/include/vendored/lua/src/lctype.c b/include/vendored/lua/src/lctype.cpp similarity index 100% rename from include/vendored/lua/src/lctype.c rename to include/vendored/lua/src/lctype.cpp diff --git a/include/vendored/lua/src/ldblib.c b/include/vendored/lua/src/ldblib.cpp similarity index 100% rename from include/vendored/lua/src/ldblib.c rename to include/vendored/lua/src/ldblib.cpp diff --git a/include/vendored/lua/src/ldebug.c b/include/vendored/lua/src/ldebug.cpp similarity index 100% rename from include/vendored/lua/src/ldebug.c rename to include/vendored/lua/src/ldebug.cpp diff --git a/include/vendored/lua/src/ldo.c b/include/vendored/lua/src/ldo.cpp similarity index 100% rename from include/vendored/lua/src/ldo.c rename to include/vendored/lua/src/ldo.cpp diff --git a/include/vendored/lua/src/ldump.c b/include/vendored/lua/src/ldump.cpp similarity index 100% rename from include/vendored/lua/src/ldump.c rename to include/vendored/lua/src/ldump.cpp diff --git a/include/vendored/lua/src/lfunc.c b/include/vendored/lua/src/lfunc.cpp similarity index 100% rename from include/vendored/lua/src/lfunc.c rename to include/vendored/lua/src/lfunc.cpp diff --git a/include/vendored/lua/src/lgc.c b/include/vendored/lua/src/lgc.cpp similarity index 100% rename from include/vendored/lua/src/lgc.c rename to include/vendored/lua/src/lgc.cpp diff --git a/include/vendored/lua/src/linit.c b/include/vendored/lua/src/linit.cpp similarity index 100% rename from include/vendored/lua/src/linit.c rename to include/vendored/lua/src/linit.cpp diff --git a/include/vendored/lua/src/liolib.c b/include/vendored/lua/src/liolib.cpp similarity index 100% rename from include/vendored/lua/src/liolib.c rename to include/vendored/lua/src/liolib.cpp diff --git a/include/vendored/lua/src/llex.c b/include/vendored/lua/src/llex.cpp similarity index 100% rename from include/vendored/lua/src/llex.c rename to include/vendored/lua/src/llex.cpp diff --git a/include/vendored/lua/src/lmathlib.c b/include/vendored/lua/src/lmathlib.cpp similarity index 100% rename from include/vendored/lua/src/lmathlib.c rename to include/vendored/lua/src/lmathlib.cpp diff --git a/include/vendored/lua/src/lmem.c b/include/vendored/lua/src/lmem.cpp similarity index 100% rename from include/vendored/lua/src/lmem.c rename to include/vendored/lua/src/lmem.cpp diff --git a/include/vendored/lua/src/loadlib.c b/include/vendored/lua/src/loadlib.cpp similarity index 100% rename from include/vendored/lua/src/loadlib.c rename to include/vendored/lua/src/loadlib.cpp diff --git a/include/vendored/lua/src/lobject.c b/include/vendored/lua/src/lobject.cpp similarity index 100% rename from include/vendored/lua/src/lobject.c rename to include/vendored/lua/src/lobject.cpp diff --git a/include/vendored/lua/src/lopcodes.c b/include/vendored/lua/src/lopcodes.cpp similarity index 100% rename from include/vendored/lua/src/lopcodes.c rename to include/vendored/lua/src/lopcodes.cpp diff --git a/include/vendored/lua/src/loslib.c b/include/vendored/lua/src/loslib.cpp similarity index 100% rename from include/vendored/lua/src/loslib.c rename to include/vendored/lua/src/loslib.cpp diff --git a/include/vendored/lua/src/lparser.c b/include/vendored/lua/src/lparser.cpp similarity index 100% rename from include/vendored/lua/src/lparser.c rename to include/vendored/lua/src/lparser.cpp diff --git a/include/vendored/lua/src/lstate.c b/include/vendored/lua/src/lstate.cpp similarity index 100% rename from include/vendored/lua/src/lstate.c rename to include/vendored/lua/src/lstate.cpp diff --git a/include/vendored/lua/src/lstring.c b/include/vendored/lua/src/lstring.cpp similarity index 100% rename from include/vendored/lua/src/lstring.c rename to include/vendored/lua/src/lstring.cpp diff --git a/include/vendored/lua/src/lstrlib.c b/include/vendored/lua/src/lstrlib.cpp similarity index 100% rename from include/vendored/lua/src/lstrlib.c rename to include/vendored/lua/src/lstrlib.cpp diff --git a/include/vendored/lua/src/ltable.c b/include/vendored/lua/src/ltable.cpp similarity index 100% rename from include/vendored/lua/src/ltable.c rename to include/vendored/lua/src/ltable.cpp diff --git a/include/vendored/lua/src/ltablib.c b/include/vendored/lua/src/ltablib.cpp similarity index 100% rename from include/vendored/lua/src/ltablib.c rename to include/vendored/lua/src/ltablib.cpp diff --git a/include/vendored/lua/src/ltm.c b/include/vendored/lua/src/ltm.cpp similarity index 100% rename from include/vendored/lua/src/ltm.c rename to include/vendored/lua/src/ltm.cpp diff --git a/include/vendored/lua/src/luac.c b/include/vendored/lua/src/luac.cpp similarity index 100% rename from include/vendored/lua/src/luac.c rename to include/vendored/lua/src/luac.cpp diff --git a/include/vendored/lua/src/lundump.c b/include/vendored/lua/src/lundump.cpp similarity index 100% rename from include/vendored/lua/src/lundump.c rename to include/vendored/lua/src/lundump.cpp diff --git a/include/vendored/lua/src/lutf8lib.c b/include/vendored/lua/src/lutf8lib.cpp similarity index 100% rename from include/vendored/lua/src/lutf8lib.c rename to include/vendored/lua/src/lutf8lib.cpp diff --git a/include/vendored/lua/src/lvm.c b/include/vendored/lua/src/lvm.cpp similarity index 100% rename from include/vendored/lua/src/lvm.c rename to include/vendored/lua/src/lvm.cpp diff --git a/include/vendored/lua/src/lzio.c b/include/vendored/lua/src/lzio.cpp similarity index 100% rename from include/vendored/lua/src/lzio.c rename to include/vendored/lua/src/lzio.cpp diff --git a/include/visualisationState.h b/include/visualisationState.h index ea97569f..ca3bf521 100644 --- a/include/visualisationState.h +++ b/include/visualisationState.h @@ -111,6 +111,7 @@ struct VisualisationState text = ""; frame = 0; + elementsUpdated = true; } std::vector & atoms; @@ -131,6 +132,8 @@ struct VisualisationState bool recording = false; bool recordClosing = false; + bool elementsUpdated = false; + /** * @brief Video writing is behind. * diff --git a/src/main.cpp b/src/main.cpp index 5b9b5b09..08aafa01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,7 @@ #include +#include + std::string Console::stackTrace(""); int main(int argv, char ** argc) @@ -45,7 +47,6 @@ int main(int argv, char ** argc) double delta = 0; unsigned frameId = 0; bool readInProgress = false; - bool elementsNeedUpdate = false; bool playBackward = false; uint8_t lastAutoPlayIncrement = 0; @@ -108,8 +109,7 @@ int main(int argv, char ** argc) Camera camera {structure->atoms, resX, resY, options.fieldOfView.value}; - jLog::Log log; - Console console(log, &visualisationState, &options, &camera); + Console console(&visualisationState, &options, &camera); AtomRenderer atomRenderer ( @@ -141,8 +141,6 @@ int main(int argv, char ** argc) structure->getCellC() ); - elementsNeedUpdate = true; - atomRenderer.updateCamera(camera); bondRenderer.updateCamera(camera); if (!options.noTransparencySorting.value) @@ -157,6 +155,7 @@ int main(int argv, char ** argc) display.initImgui(); loadFonts(); + ConsoleWindow consoleWindow; jGLInstance->setClear(theme.background); @@ -185,120 +184,124 @@ int main(int argv, char ** argc) } } - if (display.keyHasEvent(GLFW_KEY_V, jGL::EventType::PRESS)) - { - visualisationState.toggleRecord(options); - } + visualisationState.elementsUpdated = false; + camera.updated = false; - if (visualisationState.recordClosing && visualisationState.record->finalise()) + if (!consoleWindow.focussed) { - visualisationState.record.reset(); - visualisationState.recording = false; - visualisationState.recordClosing = false; - } - if (display.keyHasEvent(GLFW_KEY_H, jGL::EventType::PRESS)) - { - options.hideAtoms.value = !options.hideAtoms.value; - } + if (display.keyHasEvent(GLFW_KEY_V, jGL::EventType::PRESS)) + { + visualisationState.toggleRecord(options); + } - if (display.keyHasEvent(GLFW_KEY_U, jGL::EventType::PRESS)) - { - options.hideUI.value = !options.hideUI.value; - } + if (display.keyHasEvent(GLFW_KEY_H, jGL::EventType::PRESS)) + { + options.hideAtoms.value = !options.hideAtoms.value; + } - bool cameraMoved = cameraControls - ( - display, - camera, - options.cameraZoomSpeed.value, - options.cameraRotateSpeed.value, - options.cameraInclineSpeed.value - ); - - elementsNeedUpdate = atomControls - ( - display, - structure->atoms, - visualisationState.emphasisControls, - visualisationState.elementMap, - visualisationState.atomEmphasisOverrides, - options.deemphasisAlpha.value, - options.cameraPanSpeed.value - ); - - CameraWindow::CameraUpdates updates = CameraWindow().applyQueueActions(camera, structure->atoms, options, dr, dtheta, dphi); - cameraMoved = cameraMoved || updates.cameraMoved; - elementsNeedUpdate = elementsNeedUpdate || updates.atomsMoved; - - if (display.keyHasAnyEvents(GLFW_KEY_SPACE, {jGL::EventType::PRESS, jGL::EventType::HOLD})) - { - if (!options.noCentering.value) { center(structure->atoms); } - if (options.focus.value < structure->atoms.size()) { centerOn(structure->atoms, options.focus.value); } - camera.reset(structure->atoms); - elementsNeedUpdate = true; - cameraMoved = true; - } + if (display.keyHasEvent(GLFW_KEY_U, jGL::EventType::PRESS)) + { + options.hideUI.value = !options.hideUI.value; + } - if (display.keyHasAnyEvents(GLFW_KEY_F, {jGL::EventType::PRESS, jGL::EventType::HOLD})) - { - playBackward = false; - if (!readInProgress) + cameraControls + ( + display, + camera, + options.cameraZoomSpeed.value, + options.cameraRotateSpeed.value, + options.cameraInclineSpeed.value + ); + + visualisationState.elementsUpdated = atomControls + ( + display, + structure->atoms, + visualisationState.emphasisControls, + visualisationState.elementMap, + visualisationState.atomEmphasisOverrides, + options.deemphasisAlpha.value, + options.cameraPanSpeed.value + ); + + if (display.keyHasAnyEvents(GLFW_KEY_SPACE, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { - com = getCenter(structure->atoms); - structure->readFrame(structure->framePosition()); - readInProgress = true; + if (!options.noCentering.value) { center(structure->atoms); } + if (options.focus.value < structure->atoms.size()) { centerOn(structure->atoms, options.focus.value); } + camera.reset(structure->atoms); + visualisationState.elementsUpdated = true; } - } - if (display.keyHasAnyEvents(GLFW_KEY_B, {jGL::EventType::PRESS, jGL::EventType::HOLD})) - { - playBackward = true; - if (!readInProgress) + if (display.keyHasAnyEvents(GLFW_KEY_F, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { - com = getCenter(structure->atoms); - backward(structure); - readInProgress = true; + playBackward = false; + if (!readInProgress) + { + com = getCenter(structure->atoms); + structure->readFrame(structure->framePosition()); + readInProgress = true; + } } - } - if (display.keyHasEvent(GLFW_KEY_R, jGL::EventType::PRESS)) - { - if (!readInProgress) + if (display.keyHasAnyEvents(GLFW_KEY_B, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { - structure->readFrame(0); - readInProgress = true; + playBackward = true; + if (!readInProgress) + { + com = getCenter(structure->atoms); + backward(structure); + readInProgress = true; + } } - } - if (display.keyHasEvent(GLFW_KEY_X, jGL::EventType::PRESS)) - { - options.showAxes.value = !options.showAxes.value; - } + if (display.keyHasEvent(GLFW_KEY_R, jGL::EventType::PRESS)) + { + if (!readInProgress) + { + structure->readFrame(0); + readInProgress = true; + } + } - if (display.keyHasEvent(GLFW_KEY_C, jGL::EventType::PRESS)) - { - options.showCell.value = !options.showCell.value; - } + if (display.keyHasEvent(GLFW_KEY_X, jGL::EventType::PRESS)) + { + options.showAxes.value = !options.showAxes.value; + } - if (display.keyHasEvent(GLFW_KEY_P, jGL::EventType::PRESS)) - { - options.play.value = !options.play.value; - } + if (display.keyHasEvent(GLFW_KEY_C, jGL::EventType::PRESS)) + { + options.showCell.value = !options.showCell.value; + } - if (display.keyHasAnyEvents(GLFW_KEY_K, {jGL::EventType::PRESS, jGL::EventType::HOLD})) - { - options.speed.value = std::min(options.speed.value+1, 60); - } + if (display.keyHasEvent(GLFW_KEY_P, jGL::EventType::PRESS)) + { + options.play.value = !options.play.value; + } - if (display.keyHasAnyEvents(GLFW_KEY_J, {jGL::EventType::PRESS, jGL::EventType::HOLD})) - { - if (options.speed.value > 1) + if (display.keyHasAnyEvents(GLFW_KEY_K, {jGL::EventType::PRESS, jGL::EventType::HOLD})) { - options.speed.value--; + options.speed.value = std::min(options.speed.value+1, 60); + } + + if (display.keyHasAnyEvents(GLFW_KEY_J, {jGL::EventType::PRESS, jGL::EventType::HOLD})) + { + if (options.speed.value > 1) + { + options.speed.value--; + } } } + if (visualisationState.recordClosing && visualisationState.record->finalise()) + { + visualisationState.record.reset(); + visualisationState.recording = false; + visualisationState.recordClosing = false; + } + + CameraWindow().applyQueueActions(camera, structure->atoms, visualisationState.elementsUpdated, options, dr, dtheta, dphi); + if (readInProgress && structure->frameReadComplete()) { // Previous threaded read is done. @@ -315,13 +318,14 @@ int main(int argv, char ** argc) applyColours(structure->atoms, visualisationState.atomColourOverrides); applySizes(structure->atoms, visualisationState.atomSizes); cell.setVectors(structure->getCellA(), structure->getCellB(), structure->getCellC()); - elementsNeedUpdate = true; + visualisationState.elementsUpdated = true; } - if (cameraMoved) + if (camera.updated) { atomRenderer.updateCamera(camera); bondRenderer.updateCamera(camera); + camera.updated = false; } if (!readInProgress && std::filesystem::exists(options.script.value)) @@ -332,10 +336,10 @@ int main(int argv, char ** argc) applySizes(structure->atoms, visualisationState.atomSizes); atomRenderer.updateCamera(camera); bondRenderer.updateCamera(camera); - elementsNeedUpdate = true; + visualisationState.elementsUpdated = true; } - if (elementsNeedUpdate) + if (visualisationState.elementsUpdated) { if (!options.hideAtoms.value) { @@ -347,6 +351,7 @@ int main(int argv, char ** argc) { setTransparencySorting(structure->atoms, atomRenderer, bondRenderer); } + visualisationState.elementsUpdated = false; } bondRenderer.draw(); @@ -368,7 +373,7 @@ int main(int argv, char ** argc) infoWindow(structure, camera, visualisationState, delta); CameraWindow().draw(options); - + consoleWindow.draw("Console", console); ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } @@ -429,7 +434,7 @@ int main(int argv, char ** argc) jGLInstance->endFrame(); - if (!closing && elementsNeedUpdate) + if (!closing && visualisationState.elementsUpdated) { visualisationState.recordFrame(resX, resY); } @@ -452,7 +457,6 @@ int main(int argv, char ** argc) auto toc = std::chrono::high_resolution_clock::now(); deltas[frameId] = std::chrono::duration_cast(toc-tic).count(); frameId = (frameId+1) % 60; - if (frameId == 0 && log.size() > 0) { std::cout << log << "\n"; } } jGLInstance->finish(); diff --git a/tests/models/models.h b/tests/models/models.h index 536d2463..e4ff26b9 100644 --- a/tests/models/models.h +++ b/tests/models/models.h @@ -11,8 +11,6 @@ #include -#include - #include #include #include diff --git a/tests/test_console/test_console.cpp b/tests/test_console/test_console.cpp index 7c77fede..7bb51afa 100644 --- a/tests/test_console/test_console.cpp +++ b/tests/test_console/test_console.cpp @@ -23,10 +23,9 @@ Camera camera(testAtoms, 64, 64, 60.0); SCENARIO("Lua atom interop") { - jLog::Log l; GIVEN("A Lua console") { - Console console(l, &vs, &options, &camera); + Console console(&vs, &options, &camera); WHEN("The script \"atoms = sfoav.atomCount()\" is run") { console.runString("atoms = sfoav.atomCount()"); @@ -289,11 +288,10 @@ SCENARIO("Lua atom interop") SCENARIO("Lua bond interop") { - jLog::Log l; GIVEN("A Lua console (and no bonds)") { vs.bonds.clear(); - Console console(l, &vs, &options, &camera); + Console console(&vs, &options, &camera); WHEN("The script \"empty = next(sfoav.getAtomsBonds(0))==nil\" is run") { console.runString("empty = next(sfoav.getAtomsBonds(0))==nil"); @@ -353,10 +351,9 @@ SCENARIO("Lua bond interop") SCENARIO("Lua camera interop") { - jLog::Log l; GIVEN("A Lua console and a camera at spherical coordinates (1,3.14,1.57) and 60 fov.") { - Console console(l, &vs, &options, &camera); + Console console(&vs, &options, &camera); camera.setPosition({1,3.14,1.57}); WHEN("The script \"x, y, z = sfoav.cameraPosition(true)\"") { @@ -449,10 +446,9 @@ SCENARIO("Lua camera interop") */ SCENARIO("Lua options interop") { - jLog::Log l; GIVEN("A Lua console with default CommandLine values") { - Console console(l, &vs, &options, &camera); + Console console(&vs, &options, &camera); WHEN("The script \"v = sfoav.getOption(\"meshes\");\"") {