Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Scripting/angelscript/asdebugger.cpp')
-rw-r--r--Source/Scripting/angelscript/asdebugger.cpp795
1 files changed, 795 insertions, 0 deletions
diff --git a/Source/Scripting/angelscript/asdebugger.cpp b/Source/Scripting/angelscript/asdebugger.cpp
new file mode 100644
index 00000000..43bd220d
--- /dev/null
+++ b/Source/Scripting/angelscript/asdebugger.cpp
@@ -0,0 +1,795 @@
+//-----------------------------------------------------------------------------
+// Name: asdebugger.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include "asdebugger.h"
+
+#include <GUI/dimgui/dimgui.h>
+#include <GUI/dimgui/imgui_impl_sdl_gl3.h>
+
+#include <Scripting/angelscript/ascontext.h>
+#include <Scripting/angelscript/add_on/scriptarray/scriptarray.h>
+
+#include <Main/engine.h>
+#include <Graphics/graphics.h>
+#include <UserInput/input.h>
+
+#include <angelscript.h>
+
+#include <set>
+
+std::vector<ASContext*> ASDebugger::active_contexts;
+std::vector<std::pair<std::string, int> > ASDebugger::global_breakpoints;
+
+ASDebugger::ASDebugger()
+ : paused(false)
+ , break_next(false)
+ , current_line(-1)
+ , current_stack_level(0)
+ , ctx(NULL)
+ , auto_scroll(false)
+ , show_local_variables(false)
+ , show_global_variables(false)
+ , show_stack_trace(false)
+{
+ for(size_t i = 0; i < global_breakpoints.size(); ++i) {
+ ToggleBreakpoint(global_breakpoints[i].first.c_str(), global_breakpoints[i].second);
+ }
+}
+
+ASDebugger::~ASDebugger() {
+}
+
+void ASDebugger::AddContext(ASContext* context) {
+ bool add = true;
+ for(size_t i = 0; i < active_contexts.size(); ++i) {
+ if(active_contexts[i] == context) {
+ add = false;
+ break;
+ }
+ }
+
+ if(add)
+ active_contexts.push_back(context);
+}
+
+void ASDebugger::RemoveContext(ASContext* context) {
+ for(size_t i = 0; i < active_contexts.size(); ++i) {
+ if(active_contexts[i] == context) {
+ active_contexts.erase(active_contexts.begin() + i);
+ break;
+ }
+ }
+}
+
+const std::vector<ASContext*>& ASDebugger::GetActiveContexts() {
+ return active_contexts;
+}
+
+void ASDebugger::AddGlobalBreakpoint(const char* file, int line) {
+ bool found = false;
+ for(size_t i = 0; i < global_breakpoints.size(); ++i) {
+ if(strcmp(global_breakpoints[i].first.c_str(), file) == 0 && global_breakpoints[i].second == line) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found) {
+ global_breakpoints.push_back(std::pair<std::string, int>(file, line));
+ for(size_t i = 0; i < active_contexts.size(); ++i) {
+ active_contexts[i]->dbg.AddBreakpoint(file, line);
+ }
+ }
+}
+
+void ASDebugger::RemoveGlobalBreakpoint(const char* file, int line) {
+ for(size_t i = 0; i < global_breakpoints.size(); ++i) {
+ if(strcmp(global_breakpoints[i].first.c_str(), file) == 0 && global_breakpoints[i].second == line) {
+ global_breakpoints.erase(global_breakpoints.begin() + i);
+ for(size_t i = 0; i < active_contexts.size(); ++i) {
+ active_contexts[i]->dbg.RemoveBreakpoint(file, line);
+ }
+ break;
+ }
+ }
+}
+
+const std::vector<std::pair<std::string, int> >& ASDebugger::GetGlobalBreakpoints() {
+ return global_breakpoints;
+}
+
+void ASDebugger::SetModule(ASModule* module) {
+ this->module = module;
+}
+
+void ASDebugger::PrintCType(Variable& variable, asIScriptContext* ctx) {
+ void* ptr = variable.ptr;
+ if(variable.type_id & asTYPEID_OBJHANDLE) {
+ ptr = *(void**)ptr;
+ if(!ptr) {
+ ImGui::Text("%s points to null", variable.name);
+ return;
+ }
+ }
+
+ if(variable.type_id & asTYPEID_SCRIPTOBJECT) {
+ if(ImGui::TreeNodeEx(variable.name, 0)) {
+ asIScriptObject* obj = (asIScriptObject*)ptr;
+ for(asUINT i = 0; i < obj->GetPropertyCount(); ++i) {
+ Variable member;
+ member.type_id = obj->GetPropertyTypeId(i);
+ member.name = obj->GetPropertyName(i);
+ member.ptr = obj->GetAddressOfProperty(i);
+ PrintVar(member, ctx);
+ }
+ ImGui::TreePop();
+ }
+ return;
+ }
+ asITypeInfo* info = ctx->GetEngine()->GetTypeInfoById(variable.type_id);
+ if(strcmp(info->GetName(), "string") == 0) {
+ std::string* string = (std::string*)ptr;
+ if(string) {
+ ImGui::Text("%s = \"%s\"", variable.name, string->c_str());
+ } else {
+ ImGui::Text("%s = ?", variable.name);
+ }
+ } else if(strcmp(info->GetName(), "array") == 0) {
+ if(ImGui::TreeNodeEx(variable.name, 0)) {
+ CScriptArray* arr = (CScriptArray*)ptr;
+ int new_type_id = info->GetSubTypeId(0);
+ for(size_t i = 0; i < arr->GetSize(); ++i) {
+ char buffer[16];
+ sprintf(buffer, "[%d]", (int)i);
+ Variable variable;
+ variable.name = buffer;
+ variable.type_id = new_type_id;
+ variable.ptr = arr->At(i);
+ PrintVar(variable, ctx);
+ }
+ ImGui::TreePop();
+ }
+ } else {
+ if(info->GetPropertyCount() > 0) {
+ if(ImGui::TreeNodeEx(variable.name, 0)) {
+ for(size_t i = 0; i < info->GetPropertyCount(); ++i) {
+ int property_offset;
+ Variable property;
+ info->GetProperty(i, &property.name, &property.type_id, NULL, NULL, &property_offset);
+ property.ptr = (char*)ptr + property_offset;
+ PrintVar(property, ctx);
+ }
+
+ ImGui::TreePop();
+ }
+ } else {
+ ImGui::Text("%s is of unknown type %s and no members are registered", variable.name, info->GetName());
+ }
+ }
+}
+
+void ASDebugger::PrintVar(Variable& variable, asIScriptContext* ctx) {
+ switch(variable.type_id) {
+ case asTYPEID_BOOL:
+ ImGui::Text("%s = %d\n", variable.name, *(bool*)variable.ptr);
+ break;
+ case asTYPEID_INT8:
+ ImGui::Text("%s = %d\n", variable.name, (int)*(int8_t*)variable.ptr);
+ break;
+ case asTYPEID_INT16:
+ ImGui::Text("%s = %d\n", variable.name, (int)*(int16_t*)variable.ptr);
+ break;
+ case asTYPEID_INT32:
+ ImGui::Text("%s = %ld\n", variable.name, (long)(*(int32_t*)variable.ptr)); // These casts are done to avoid warnings on 32/64 bit builds
+ break;
+ case asTYPEID_INT64:
+ ImGui::Text("%s = %lld\n", variable.name, (long long)(*(int64_t*)variable.ptr));
+ break;
+ case asTYPEID_UINT8:
+ ImGui::Text("%s = %u\n", variable.name, (unsigned int)*(uint8_t*)variable.ptr);
+ break;
+ case asTYPEID_UINT16:
+ ImGui::Text("%s = %u\n", variable.name, (unsigned int)*(uint16_t*)variable.ptr);
+ break;
+ case asTYPEID_UINT32:
+ ImGui::Text("%s = %lu\n", variable.name, (unsigned long)(*(uint32_t*)variable.ptr));
+ break;
+ case asTYPEID_UINT64:
+ ImGui::Text("%s = %llu\n", variable.name, (unsigned long long)(*(uint64_t*)variable.ptr));
+ break;
+ case asTYPEID_FLOAT:
+ case asTYPEID_DOUBLE:
+ ImGui::Text("%s = %f\n", variable.name, *(float*)variable.ptr);
+ break;
+ default: {
+ if(variable.ptr == NULL)
+ return;
+ PrintCType(variable, ctx);
+ return;
+ }
+ }
+}
+
+void ASDebugger::Print() {
+ std::set<void*> printed_variables;
+ asUINT callstack_size = ctx->GetCallstackSize();
+ for(asUINT stack_level = 0; stack_level < callstack_size; ++stack_level) {
+ int variable_count = ctx->GetVarCount(stack_level);
+
+ for(int var_index = 0; var_index < variable_count; ++var_index) {
+ Variable variable;
+ variable.name = ctx->GetVarName(var_index, stack_level);
+ variable.type_id = ctx->GetVarTypeId(var_index, stack_level);
+ variable.ptr = ctx->GetAddressOfVar(var_index, stack_level);
+
+ if(printed_variables.find(variable.ptr) != printed_variables.end())
+ continue;
+ printed_variables.insert(variable.ptr);
+ local_variables.push_back(variable);
+ }
+ }
+
+ asIScriptFunction* function = ctx->GetFunction();
+ if(!function)
+ return;
+ asIScriptModule* script_mod = function->GetModule();
+ if(!script_mod)
+ return;
+
+ for(asUINT variable_index = 0; variable_index < script_mod->GetGlobalVarCount(); ++variable_index) {
+ Variable variable;
+ script_mod->GetGlobalVar(variable_index, &variable.name, NULL, &variable.type_id);
+ variable.ptr = script_mod->GetAddressOfGlobalVar(variable_index);
+ if(printed_variables.find(variable.ptr) != printed_variables.end())
+ continue;
+ printed_variables.insert(variable.ptr);
+ global_variables.push_back(variable);
+ }
+
+ asIScriptEngine* engine = ctx->GetEngine();
+ for(asUINT variable_index = 0; variable_index < engine->GetGlobalPropertyCount(); ++variable_index) {
+ Variable variable;
+ engine->GetGlobalPropertyByIndex(variable_index, &variable.name, NULL, &variable.type_id, NULL, NULL, &variable.ptr);
+ if(printed_variables.find(variable.ptr) != printed_variables.end())
+ continue;
+ printed_variables.insert(variable.ptr);
+ global_variables.push_back(variable);
+ }
+}
+
+void ASDebugger::Break() {
+ break_next = true;
+ auto_scroll = true;
+}
+
+void ASDebugger::ToggleBreakpoint(const char* file_name, int line) {
+ std::string file(file_name);
+
+ Breakpoint_iter breakpoint_iter = breakpoints.find(file);
+ if(breakpoint_iter == breakpoints.end())
+ breakpoints.insert(std::pair<std::string, std::vector<int> >(file, std::vector<int>(1, line)));
+ else
+ {
+ std::vector<int>& lines = breakpoint_iter->second;
+
+ for(size_t i = 0; i < lines.size(); ++i) {
+ if(lines[i] == line) {
+ lines.erase(lines.begin() + i);
+ return;
+ }
+ }
+
+ breakpoint_iter->second.push_back(line);
+ }
+}
+
+void ASDebugger::AddBreakpoint(const char* file_name, int line) {
+ std::string file(file_name);
+
+ Breakpoint_iter breakpoint_iter = breakpoints.find(file);
+ if(breakpoint_iter == breakpoints.end())
+ breakpoints.insert(std::pair<std::string, std::vector<int> >(file, std::vector<int>(1, line)));
+ else
+ {
+ std::vector<int>& lines = breakpoint_iter->second;
+
+ for(size_t i = 0; i < lines.size(); ++i) {
+ if(lines[i] == line) {
+ return;
+ }
+ }
+
+ breakpoint_iter->second.push_back(line);
+ }
+}
+
+void ASDebugger::RemoveBreakpoint(const char* file_name, int line) {
+ std::string file(file_name);
+
+ Breakpoint_iter breakpoint_iter = breakpoints.find(file);
+ if(breakpoint_iter != breakpoints.end())
+ {
+ std::vector<int>& lines = breakpoint_iter->second;
+
+ for(size_t i = 0; i < lines.size(); ++i) {
+ if(lines[i] == line) {
+ lines.erase(lines.begin() + i);
+ return;
+ }
+ }
+ }
+}
+
+const std::vector<int>* ASDebugger::GetBreakpoints(const char* file_name) {
+ std::string file(file_name);
+
+ Breakpoint_iter breakpoint_iter = breakpoints.find(file);
+ if(breakpoint_iter != breakpoints.end())
+ return &(breakpoint_iter->second);
+ else
+ return NULL;
+}
+
+void ASDebugger::LineCallback(asIScriptContext* ctx) {
+ if(paused) {
+ // After suspending, the line callback is called once again
+ local_variables.clear();
+ global_variables.clear();
+ Print();
+ DebugLoop();
+ return;
+ }
+ this->ctx = ctx;
+
+ LineFile lf = GetLF(ctx);
+
+ current_file = lf.file;
+ current_line = lf.line_number;
+
+ if(break_next) {
+ break_next = false;
+ paused = true;
+ ctx->Suspend();
+ return;
+ }
+
+ std::string file_path = lf.file.GetOriginalPathStr();
+ file_path = file_path.substr(file_path.find_last_of("\\/") + 1);
+
+ const std::vector<int>* breakpoints = GetBreakpoints(file_path.c_str());
+ if(breakpoints == NULL)
+ return;
+ else {
+ for(size_t i = 0; i < breakpoints->size(); ++i) {
+ if(breakpoints->at(i) == current_line) {
+ paused = true;
+ auto_scroll = true;
+ ctx->Suspend();
+ }
+ }
+ }
+}
+
+void ASDebugger::StepOver(asIScriptContext* ctx) {
+ LineFile lf = GetLF(ctx);
+
+ int stack_level = ctx->GetCallstackSize();
+
+ if(stack_level <= current_stack_level) {
+ current_file = lf.file;
+ current_line = lf.line_number;
+ ctx->Suspend();
+ paused = true;
+ auto_scroll = true;
+ } else {
+ Continue(ctx);
+ }
+}
+
+void ASDebugger::StepInto(asIScriptContext* ctx) {
+ LineFile lf = GetLF(ctx);
+
+ if((int)lf.line_number != current_line) {
+ current_file = lf.file;
+ current_line = lf.line_number;
+ ctx->Suspend();
+ paused = true;
+ auto_scroll = true;
+ }
+}
+
+void ASDebugger::StepOut(asIScriptContext* ctx) {
+ int stack_level = ctx->GetCallstackSize();
+
+ if(stack_level < current_stack_level) {
+ LineFile lf = GetLF(ctx);
+ current_file = lf.file;
+ current_line = lf.line_number;
+ ctx->Suspend();
+ paused = true;
+ auto_scroll = true;
+ }
+}
+
+void ASDebugger::Continue(asIScriptContext* ctx) {
+ LineFile lf = GetLF(ctx);
+ if((int)lf.line_number != current_line)
+ continue_break = true;
+
+ if(continue_break) {
+ std::string file_path = lf.file.GetOriginalPathStr();
+ file_path = file_path.substr(file_path.find_last_of("\\/") + 1);
+
+ const std::vector<int>* breakpoints = GetBreakpoints(file_path.c_str());
+ if(breakpoints == NULL)
+ return;
+ else {
+ for(size_t i = 0; i < breakpoints->size(); ++i) {
+ if(breakpoints->at(i) == (int)lf.line_number) {
+ current_file = lf.file;
+ current_line = lf.line_number;
+ ctx->Suspend();
+ paused = true;
+ auto_scroll = true;
+ }
+ }
+ }
+ }
+}
+
+void ASDebugger::DebugLoop() {
+ Graphics* graphics = Graphics::Instance();
+ Input* input = Input::Instance();
+
+ input->cursor->SetVisible(true);
+ input->SetGrabMouse(false);
+ while(paused) {
+ ctx->ClearLineCallback();
+ PollEvents();
+
+ bool imgui_begun = true; //ImGui::FrameBegun();
+ if(imgui_begun) {
+ ImGui::EndFrame();
+ }
+
+ ImGui_ImplSdlGL3_NewFrame(graphics->sdl_window_, input->GetGrabMouse());
+ bool update_variables = true;
+ switch(UpdateGUI())
+ {
+ case CONTINUE:
+ continue_break = false;
+ ctx->SetLineCallback(asMETHOD(ASDebugger, Continue), this, asCALL_THISCALL);
+ paused = false;
+ do {
+ int ret = ctx->Execute();
+ if(ret == asEXECUTION_FINISHED) {
+ ctx->SetLineCallback(asMETHOD(ASDebugger, LineCallback), this, asCALL_THISCALL);
+ ImGui::Render();
+ if(imgui_begun) {
+ ImGui_ImplSdlGL3_NewFrame(graphics->sdl_window_, input->GetGrabMouse());
+ }
+ return;
+ }
+ } while(!paused);
+ break;
+ case OVER:
+ current_stack_level = ctx->GetCallstackSize();
+ ctx->SetLineCallback(asMETHOD(ASDebugger, StepOver), this, asCALL_THISCALL);
+ paused = false;
+ do {
+ int ret = ctx->Execute();
+ if(ret == asEXECUTION_FINISHED) {
+ ctx->SetLineCallback(asMETHOD(ASDebugger, LineCallback), this, asCALL_THISCALL);
+ ImGui::Render();
+ if(imgui_begun) {
+ ImGui_ImplSdlGL3_NewFrame(graphics->sdl_window_, input->GetGrabMouse());
+ }
+ return;
+ }
+ } while(!paused);
+ break;
+ case INTO:
+ ctx->SetLineCallback(asMETHOD(ASDebugger, StepInto), this, asCALL_THISCALL);
+ paused = false;
+ do {
+ int ret = ctx->Execute();
+ if(ret == asEXECUTION_FINISHED) {
+ ctx->SetLineCallback(asMETHOD(ASDebugger, LineCallback), this, asCALL_THISCALL);
+ ImGui::Render();
+ if(imgui_begun) {
+ ImGui_ImplSdlGL3_NewFrame(graphics->sdl_window_, input->GetGrabMouse());
+ }
+ return;
+ }
+ } while(!paused);
+ break;
+ case LEAVE:
+ current_stack_level = ctx->GetCallstackSize();
+ ctx->SetLineCallback(asMETHOD(ASDebugger, StepOut), this, asCALL_THISCALL);
+ paused = false;
+ do {
+ int ret = ctx->Execute();
+ if(ret == asEXECUTION_FINISHED) {
+ ctx->SetLineCallback(asMETHOD(ASDebugger, LineCallback), this, asCALL_THISCALL);
+ ImGui::Render();
+ if(imgui_begun) {
+ ImGui_ImplSdlGL3_NewFrame(graphics->sdl_window_, input->GetGrabMouse());
+ }
+ return;
+ }
+ } while(!paused);
+ break;
+ default:
+ update_variables = false;
+ break;
+ }
+ if(update_variables) {
+ local_variables.clear();
+ global_variables.clear();
+ Print();
+ }
+
+ // Back up state
+ std::stack<ViewportDims> viewport_dims_stack;
+ std::stack<GLuint> fbo_stack;
+
+ graphics->PushViewport(); // Viewport is set to entire window
+ graphics->PushFramebuffer(); // Framebuffer is set to 0
+ // Back these up to temporarily so no assertions fail/states change
+ viewport_dims_stack = graphics->viewport_dims_stack;
+ fbo_stack = graphics->fbo_stack;
+
+ graphics->viewport_dims_stack = std::stack<ViewportDims>();
+ graphics->fbo_stack = std::stack<GLuint>();
+
+ // Changes states
+ graphics->setViewport(0, 0, graphics->window_dims[0], graphics->window_dims[1]);
+ graphics->bindFramebuffer(0);
+ graphics->Clear(true);
+
+ // Draw
+ ImGui::Render();
+ input->cursor->Draw();
+
+ // Swap
+ graphics->SwapToScreen();
+
+ // Restore state
+ graphics->viewport_dims_stack = viewport_dims_stack;
+ graphics->fbo_stack = fbo_stack;
+ graphics->PopFramebuffer();
+ graphics->PopViewport();
+
+ static uint32_t last_time = 0;
+ uint32_t diff = 16 - (SDL_TS_GetTicks() - last_time) - 1;
+ if( diff > 15 ){
+ diff = 15;
+ }
+ SDL_Delay(diff);
+ last_time = SDL_TS_GetTicks();
+ }
+
+ ctx->SetLineCallback(asMETHOD(ASDebugger, LineCallback), this, asCALL_THISCALL);
+}
+
+void ASDebugger::PollEvents() {
+ Graphics* graphics = Graphics::Instance();
+ Input* input = Input::Instance();
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ ProcessEventImGui(&event);
+ //Redirect input events to the controller
+ switch( event.type ) {
+ case SDL_WINDOWEVENT:
+ switch(event.window.event){
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ input->HandleEvent(event);
+ break;
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ input->HandleEvent(event);
+ break;
+ }
+ break;
+ case SDL_QUIT:
+ input->RequestQuit();
+ return;
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEWHEEL:
+ if(!WantMouseImGui()){
+ input->HandleEvent(event);
+ }
+ break;
+ case SDL_KEYDOWN:
+ case SDL_TEXTINPUT:
+ if(!WantKeyboardImGui()){
+ input->HandleEvent(event);
+ }
+ break;
+ default:
+ input->HandleEvent(event);
+ }
+ }
+}
+
+void ASDebugger::VariablesMenu(const char* window_name, ImGuiTextFilter& filter, std::vector<Variable>& variables, bool& show_variables) {
+ if(show_variables) {
+ ImGui::SetNextWindowSize(ImVec2(640.0f, 480.0f), ImGuiCond_FirstUseEver);
+ ImGui::Begin(window_name, &show_variables);
+ if(ImGui::InputText("Filters:", filter.InputBuf, IM_ARRAYSIZE(filter.InputBuf))) {
+ filter.Build();
+ }
+
+ if(filter.IsActive()) {
+ for(size_t i = 0; i < variables.size(); ++i) {
+ if(filter.PassFilter(variables[i].name)) {
+ ImGui::PushID(i);
+ PrintVar(variables[i], ctx);
+ ImGui::PopID();
+ }
+ }
+ } else {
+ for(size_t i = 0; i < variables.size(); ++i) {
+ ImGui::PushID(i);
+ PrintVar(variables[i], ctx);
+ ImGui::PopID();
+ }
+ }
+ ImGui::End();
+ }
+}
+
+static char as_debugger_buffer[512];
+static ImGuiTextFilter local_filter;
+static ImGuiTextFilter global_filter;
+ASDebugger::BreakAction ASDebugger::UpdateGUI() {
+ BreakAction action = NONE;
+
+ ImGui::SetNextWindowSize(ImVec2(1024.0f, 768.0f), ImGuiCond_FirstUseEver);
+ ImGui::Begin("Angelscript debugger", &show_performance);
+
+ ImGui::Text("Currently executing %s", current_file.resolved);
+
+ if(ImGui::Button("Continue")) {
+ action = CONTINUE;
+ }
+ ImGui::SameLine();
+ if(ImGui::Button("Step over")) {
+ action = OVER;
+ }
+ ImGui::SameLine();
+ if(ImGui::Button("Step into")) {
+ action = INTO;
+ }
+ ImGui::SameLine();
+ if(ImGui::Button("Step out")) {
+ action = LEAVE;
+ }
+
+ ImGui::Checkbox("Show local variables", &show_local_variables);
+ ImGui::SameLine();
+ ImGui::Checkbox("Show global variables", &show_global_variables);
+ ImGui::SameLine();
+ ImGui::Checkbox("Show stack trace", &show_stack_trace);
+
+ const ScriptFile* script = ScriptFileUtil::GetScriptFile(current_file);
+ const char* file_name = script->file_path.GetFullPath();
+ int last_slash = 0;
+ for(size_t i = 0; i < std::strlen(file_name); ++i) {
+ if(file_name[i] == '\\' || file_name[i] == '/')
+ last_slash = i;
+ }
+ file_name += last_slash + 1;
+
+ const std::string& script_source = script->unexpanded_contents;
+ int start_index = 0;
+ int end_index = 0;
+
+ ImGui::BeginChild("ASSourceMain", ImVec2(0,0), false, 0);
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
+ ImGui::Columns(2);
+
+ int line_nr = 1;
+
+ const int MAX_LINE_LENGTH = 255;
+ char line[MAX_LINE_LENGTH + 1];
+
+ const std::vector<int>* breakpoints = GetBreakpoints(file_name);
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
+ while(end_index != (int)script_source.size()) {
+ end_index = std::min(script_source.find('\n', start_index), script_source.size());
+
+ int copy_length = std::min(MAX_LINE_LENGTH, end_index - start_index);
+ std::memcpy(line, script_source.c_str() + start_index, copy_length);
+ line[copy_length] = '\0';
+ start_index = end_index + 1;
+
+ bool is_breakpoint = false;
+ if(breakpoints != NULL) {
+ for(size_t i = 0; i < breakpoints->size(); ++i) {
+ if(breakpoints->at(i) == line_nr) {
+ is_breakpoint = true;
+ break;
+ }
+ }
+ }
+
+ bool is_current_line = false;
+ if(line_nr == GetCurrentLine()) {
+ is_current_line = true;
+ }
+
+ if(is_current_line) {
+ if(is_breakpoint)
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.4f, 0.0f, 0.5f));
+ else
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.8f, 0.0f, 0.5f));
+
+ if(auto_scroll) {
+ ImGui::SetScrollHereY();
+ auto_scroll = false;
+ }
+ }
+ else if(is_breakpoint)
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.0f, 0.0f, 0.5f));
+
+ ImGui::Text("%d", line_nr);
+ ImGui::NextColumn();
+ ImGui::PushID(line_nr);
+ ImGui::SetColumnOffset(-1, 36);
+ if(ImGui::ButtonEx(line, ImVec2(ImGui::GetWindowWidth() - 36, 0), ImGuiButtonFlags_AlignTextBaseLine)) {
+ ToggleBreakpoint(file_name, line_nr);
+ }
+ ImGui::NextColumn();
+ ImGui::PopID();
+ if(is_current_line || is_breakpoint)
+ ImGui::PopStyleColor();
+
+ ++line_nr;
+ }
+
+ ImGui::PopStyleVar(2);
+ ImGui::PopStyleColor();
+ ImGui::EndChild();
+ ImGui::End();
+
+ if(show_stack_trace) {
+ const char* file;
+ for(asUINT i = 0; i < ctx->GetCallstackSize(); ++i) {
+ int line = ctx->GetLineNumber(i, 0, &file);
+ LineFile lineFile = module->GetCorrectedLine(line);
+ ImGui::Text("%s:%d %s", lineFile.file.GetOriginalPath(), lineFile.line_number, ctx->GetFunction(i)->GetDeclaration());
+ }
+ }
+
+ VariablesMenu("Angelscript local variables", local_filter, local_variables, show_local_variables);
+ VariablesMenu("Angelscript global variables", global_filter, global_variables, show_global_variables);
+
+ return action;
+}
+
+LineFile ASDebugger::GetLF(asIScriptContext* ctx) {
+ const char *scriptSection;
+ int line = ctx->GetLineNumber(0, 0, &scriptSection);
+ return module->GetCorrectedLine(line);
+}