diff --git a/src/CRTerm.cpp b/src/CRTerm.cpp index 299957a..3de52ce 100644 --- a/src/CRTerm.cpp +++ b/src/CRTerm.cpp @@ -19,7 +19,6 @@ #include "ConfigSelector.h" #include "ContextMenu.h" - /* SDLmain requires this. It seems to define its own main. */ #undef main @@ -119,8 +118,8 @@ int main() /* Set the cursor to normal if a UI element is online */ SDL_SetCursor(normal_cur); } - } - GPU_ClearColor(screen, SDL_Color{ 40, 40, 40, 255 }); + } + GPU_ClearColor(screen, SDL_Color{ 52, 55, 64, 255 }); /* First render the terminal */ vt100_term->VT100Render(); /* Then the UI */ diff --git a/src/CRTerm.vcxproj b/src/CRTerm.vcxproj index 6dee92b..de43169 100644 --- a/src/CRTerm.vcxproj +++ b/src/CRTerm.vcxproj @@ -108,7 +108,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ProjectDir)lib\SDL2_gpu\include;$(ProjectDir)lib\SDL2\include;$(ProjectDir)lib\imgui\include;%(AdditionalIncludeDirectories) + $(ProjectDir)lib\SDL2_gpu\include;$(ProjectDir)lib\SDL2\include;$(ProjectDir)lib\imgui\include;$(ProjectDir)include;%(AdditionalIncludeDirectories) stdcpp17 @@ -126,12 +126,16 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + $(ProjectDir)lib\SDL2_gpu\include;$(ProjectDir)lib\SDL2\include;$(ProjectDir)lib\imgui\include;$(ProjectDir)include;%(AdditionalIncludeDirectories) + stdcpp17 Console true true true + $(ProjectDir)lib\SDL2;$(ProjectDir)lib\SDL2_gpu;%(AdditionalLibraryDirectories) + SDL2main.lib;SDL2.lib;SDL2_gpu.lib;winmm.lib;Dwmapi.lib;%(AdditionalDependencies) diff --git a/src/CRTermConfig.cpp b/src/CRTermConfig.cpp index becc04c..6ea03f9 100644 --- a/src/CRTermConfig.cpp +++ b/src/CRTermConfig.cpp @@ -47,7 +47,7 @@ CRTermConfiguration::CRTermConfiguration(std::string json_path) this->default_fore_color = configuration_data.at("default_fg"); this->default_back_color = configuration_data.at("default_bg"); this->crt_warp = configuration_data.at("crt_warp"); - + this->maxlines = configuration_data.at("maxlines"); int i = 0; for (auto& color : configuration_data.at("color_scheme")) { @@ -67,9 +67,21 @@ CRTermConfiguration::CRTermConfiguration(std::string json_path) MessageBox(GetActiveWindow(), (LPCWSTR)errW.c_str(), L"Error parsing default.json", MB_OK | MB_ICONERROR); exit(-1); } + catch (nlohmann::json::other_error& error) + { + std::string err = error.what(); + std::wstring errW = std::wstring(err.begin(), err.end()); + MessageBox(GetActiveWindow(), (LPCWSTR)errW.c_str(), L"Error loading default.json", MB_OK | MB_ICONERROR); + } + catch (nlohmann::json::type_error& error) + { + std::string err = error.what(); + std::wstring errW = std::wstring(err.begin(), err.end()); + MessageBox(GetActiveWindow(), (LPCWSTR)errW.c_str(), L"Error loading default.json", MB_OK | MB_ICONERROR); + } catch (...) { - MessageBox(GetActiveWindow(), L"An exception occurred while loading default.json", L"Error loading default.json", MB_OK | MB_ICONERROR); + MessageBox(GetActiveWindow(), L"An unknown error occurred", L"Error loading default.json", MB_OK | MB_ICONERROR); } } @@ -94,6 +106,7 @@ void CRTermConfiguration::Save(std::string filename) output_json["default_fg"] = this->default_fore_color; output_json["default_bg"] = this->default_back_color; output_json["crt_warp"] = this->crt_warp; + output_json["maxlines"] = this->maxlines; int color_scheme_arr[16][3]; @@ -104,7 +117,7 @@ void CRTermConfiguration::Save(std::string filename) color_scheme_arr[i][2] = color_scheme[i].b; } - output_json["color_sheme"] = color_scheme_arr; + output_json["color_scheme"] = color_scheme_arr; std::ofstream output(filename); output << std::setw(4) << output_json; diff --git a/src/CRTermConfig.h b/src/CRTermConfig.h index 568bf2c..7bad885 100644 --- a/src/CRTermConfig.h +++ b/src/CRTermConfig.h @@ -39,6 +39,7 @@ class CRTermConfiguration int default_fore_color; int default_back_color; int blink_interval; + int maxlines; float crt_warp; CRTermColor color_scheme[16]; diff --git a/src/ConfigEditor.cpp b/src/ConfigEditor.cpp index aaa7de1..8c5d835 100644 --- a/src/ConfigEditor.cpp +++ b/src/ConfigEditor.cpp @@ -49,6 +49,10 @@ void ConfigEditor::Render(void) ImGui::SameLine(); ImGui::InputInt("##blink_interval", &(cfg->blink_interval)); + ImGui::Text("Maximum Lines"); + ImGui::SameLine(); + ImGui::InputInt("##maxlines", &(cfg->maxlines)); + ImGui::Text("Default FG"); ImGui::SameLine(); ImGui::InputInt("##default_fg", &(cfg->default_fore_color)); diff --git a/src/Console.cpp b/src/Console.cpp index c6c00e5..aa36e7e 100644 --- a/src/Console.cpp +++ b/src/Console.cpp @@ -20,6 +20,11 @@ Console::Console(CRTermConfiguration* cfg) this->cursor_x = 0; this->cursor_y = 0; + this->maxlines = cfg->maxlines; + /* Check the maxlines, if greater than 10000 or less than 500 default to 1000 */ + if (this->maxlines < CONSOLE_MIN_LINES || this->maxlines > CONSOLE_MAX_LINES) + this->maxlines = CONSOLE_DEFAULT_LINES; + this->console_resolution_x = this->console_w * this->font_w; this->console_resolution_y = this->console_h * this->font_h; @@ -194,6 +199,14 @@ void Console::HistoryDown() start_line++; } +void Console::SetSelection(bool selection, int start_x, int start_y, int end_x, int end_y) +{ + this->selected_start_x = start_x; + this->selected_start_y = start_y; + this->selected_end_x = end_x; + this->selected_end_y = end_y; + this->is_selected = selection; +} void Console::SetCursor(int x, int y) { this->cursor_x = x; @@ -317,6 +330,8 @@ unsigned char Console::ReadChar(int x, int y) return 0; return this->buffer[this->start_line * this->console_w + y * this->console_w + x]; } + +/* The Console Render function, this is what makes the magic happen :) */ void Console::Render(GPU_Target* t, int xloc, int yloc, float scale) { GPU_Clear(this->render_buffer->target); @@ -330,6 +345,8 @@ void Console::Render(GPU_Target* t, int xloc, int yloc, float scale) this->show_cursor = !this->show_cursor; this->cursor_clock = time; } + /* Set text alpha to 1.0 */ + GPU_SetUniformf(GPU_GetUniformLocation(this->text_shader_id, "alpha"), 1.0); for (int y = 0; y < this->console_h; y++) { for (int x = 0; x < this->console_w; x++) @@ -353,6 +370,35 @@ void Console::Render(GPU_Target* t, int xloc, int yloc, float scale) } } + /* Draw the scroll bar if we are scrolling i.e. last_line != start_line and the user has scrolled up */ + if (start_line != last_line) + { + GPU_Rect scrollbar; + scrollbar.h = (((float)this->console_h) / ((float)this->last_line + this->console_h)) * (this->render_buffer->h); + scrollbar.y = scrollbar.h * 0.5 * ((float)this->start_line / (float)(this->last_line + 1.0)); + scrollbar.w = 8; + scrollbar.x = this->render_buffer->w - 8; + GPU_SetUniformfv(GPU_GetUniformLocation(this->text_shader_id, "text_color"), 3, 1, this->color_scheme[this->default_fore_color].returnArray()); + /* Set scroll bar alpha to 0.8 */ + GPU_SetUniformf(GPU_GetUniformLocation(this->text_shader_id, "alpha"), 0.8); + GPU_RectangleFilled(this->render_buffer->target, scrollbar.x, scrollbar.y, scrollbar.x + scrollbar.w, scrollbar.y + scrollbar.h, SDL_Color{ 255, 255, 255, 255 }); + } + + /* Draw the selection rectangle if the user has selected some text, this bool passed from VT100 class */ + if (this->is_selected) + { + GPU_SetUniformfv(GPU_GetUniformLocation(this->text_shader_id, "text_color"), 3, 1, this->color_scheme[this->default_fore_color].returnArray()); + /* Set selected text alpha to 0.4 */ + GPU_SetUniformf(GPU_GetUniformLocation(this->text_shader_id, "alpha"), 0.4); + for (int i = this->selected_start_x + this->selected_start_y * this->console_w; i < this->selected_end_x + this->selected_end_y * this->console_w; i++) + { + + int y = i / this->console_w; + int x = i % this->console_w; + GPU_RectangleFilled(this->render_buffer->target, x * this->font_w, y * this->font_h, (x + 1) * this->font_w, (y + 1) * this->font_h, SDL_Color{ 255, 255, 255, 255 }); + } + } + /* Draw the cursor, if we are not scrolling */ if (this->show_cursor && this->start_line == this->last_line) { @@ -370,6 +416,10 @@ void Console::Render(GPU_Target* t, int xloc, int yloc, float scale) } } + /* + We have now rendered the terminal to the local render buffer, + now we pass it through the CRT shader and scale it up. + */ GPU_ActivateShaderProgram(this->crt_shader_id, &this->crt_shader_block); float resolution[2] = { (float)t->w, (float)t->h }; /* Set shader parameters */ @@ -383,17 +433,6 @@ void Console::Render(GPU_Target* t, int xloc, int yloc, float scale) /* Now blit to screen! */ GPU_BlitScale(this->render_buffer, NULL, t, xloc + (int)(this->render_buffer->w / 2) * scale, yloc + (int)(this->render_buffer->h / 2) * scale, scale, scale); GPU_DeactivateShaderProgram(); - - /* Draw the scroll bar */ - if (start_line != last_line) - { - GPU_Rect scrollbar; - scrollbar.h = (((float)this->console_h) / ((float)this->last_line + this->console_h)) * (t->h - TITLE_BAR_HEIGHT); - scrollbar.y = TITLE_BAR_HEIGHT + scrollbar.h * 0.5 * ((float)this->start_line / (float)(this->last_line + 1.0)); - scrollbar.w = SCROLL_BAR_WIDTH; - scrollbar.x = t->w - SIDES_WIDTH - SCROLL_BAR_WIDTH; - GPU_RectangleFilled2(t, scrollbar, SDL_Color{ 100, 100, 100, 255 }); - } /* Now apply the CRT effect shader The CRT effect shader applies CRT warp effect, CRT phosphor glow scanline effect, and noise. diff --git a/src/Console.h b/src/Console.h index b6c2d20..c866809 100644 --- a/src/Console.h +++ b/src/Console.h @@ -14,6 +14,10 @@ #include "CRTermConfig.h" #include "SDL_gpu.h" +#define CONSOLE_MIN_LINES 500 +#define CONSOLE_MAX_LINES 10000 +#define CONSOLE_DEFAULT_LINES 1000 + /* Helper function to construct console attributes, which are basically VGA attributes that store @@ -56,16 +60,35 @@ class Console /* TODO: Some of these are better of in private. */ unsigned char* buffer; unsigned char* attrib_buffer; + /* Character-wise resolution of the console */ int console_w, console_h; GPU_Image* console_font; GPU_Image* crt_background; int font_w, font_h; int cursor_x, cursor_y; + /* Actual resolution of the console (in pixels) */ int console_resolution_x, console_resolution_y; int default_fore_color, default_back_color; + /* No. of millseconds after which the console must blink */ int blink_interval; + /* + For scrolling, console starts drawing from start_line*console_w, last_line is the latest start_line position + For all time, start_line <= last_line. start_line is decremented when the user hits mousewheel up + and Console->HistoryUp() is called. + + maxlines is the maximum lines the console stores, beyond that, it starts to overwrite its old history. + Generally, the lower limit for maxlines is 500, and upper limit is 10000 lines. + */ int start_line, last_line; - int maxlines = 1000; + int maxlines; + + /* Selecting text into the terminal */ + bool is_selected; + int selected_start_x = 0, selected_start_y = 0; + int selected_end_x = 0, selected_end_y = 0; + /* + Stores audio data for the bell sound. + */ std::string bell_wave_file; Console(CRTermConfiguration*); @@ -86,6 +109,7 @@ class Console void ClearExt(int fromx, int fromy, int tox, int toy); void HistoryUp(); void HistoryDown(); + void SetSelection(bool selection, int start_x=0, int start_y=0, int end_x=0, int end_y=0); /* The 256 letters glyphs extracted from the font image */ GPU_Image* char_blocks[256]; diff --git a/src/VT100.cpp b/src/VT100.cpp index 6edfb30..2de84e6 100644 --- a/src/VT100.cpp +++ b/src/VT100.cpp @@ -92,7 +92,7 @@ void VT100::VT100Take(unsigned char c) { std::cout << "Unexpected identifier after VT_ESCAPE: " << c << std::endl; parser_state = VTSTATE_NORMAL; - VT100Putc(c); + //VT100Putc(c); } break; case VTSTATE_ATTR: @@ -551,9 +551,13 @@ void VT100::VT100HandleEvent(SDL_Event ev) break; case SDL_MOUSEWHEEL: if (ev.wheel.y > 0) + { this->con->HistoryUp(); + } else + { this->con->HistoryDown(); + } break; case SDL_MOUSEBUTTONUP: if (ev.button.button == SDL_BUTTON_LEFT) @@ -585,23 +589,18 @@ void VT100::VT100Send(std::string sequence) void VT100::VT100Render(void) { - con->Render(this->render_target, this->screen_offsetx, this->screen_offsety, this->font_scale); - GPU_DeactivateShaderProgram(); - /* Draw overlay above the selected text if it is selected or dragging */ if (is_selected || is_dragging) { - /* In case the user has selected it from right to left, orient the selection coords */ orientSelectedCoords(); - for (int i = this->selected_start_x + this->selected_start_y * this->con->console_w; i < this->selected_end_x + this->selected_end_y * this->con->console_w; i++) - { - int y = i / this->con->console_w; - int x = i % this->con->console_w; - int sx, sy; - consoleToScreenCoords(x, y, &sx, &sy); - GPU_RectangleFilled(this->render_target, sx, sy, sx + con->font_w * this->font_scale, sy + con->font_h * this->font_scale, SDL_Color{255, 255, 255, 128}); - } + this->con->SetSelection(true, selected_start_x, selected_start_y, selected_end_x, selected_end_y); } + else + { + this->con->SetSelection(false); + } + con->Render(this->render_target, this->screen_offsetx, this->screen_offsety, this->font_scale); + GPU_DeactivateShaderProgram(); } void VT100::VT100Shutdown() { diff --git a/src/VT100.h b/src/VT100.h index f315c68..7795896 100644 --- a/src/VT100.h +++ b/src/VT100.h @@ -115,8 +115,8 @@ class VT100 inline void consoleToScreenCoords(int conx, int cony, int* screenx, int* screeny) { - *screenx = screen_offsetx + conx * this->con->font_w * this->font_scale; - *screeny = screen_offsety + cony * this->con->font_h * this->font_scale; + *screenx = (int)((double)screen_offsetx + (double)conx * (double)this->con->font_w * this->font_scale); + *screeny = (int)((double)screen_offsety + (double)cony * (double)this->con->font_h * this->font_scale); } inline void getConsoleMouseCoords(int* conx, int* cony) diff --git a/src/resources/config/default_cmd.json b/src/resources/config/default_cmd.json index 7c98598..f926609 100644 --- a/src/resources/config/default_cmd.json +++ b/src/resources/config/default_cmd.json @@ -1,8 +1,8 @@ { "font": "font.png", - "font_width": 16, - "font_height": 32, - "font_scale": 0.8, + "font_width": 8, + "font_height": 16, + "font_scale": 1.2, "console_width": 120, "console_height": 30, "background": "crt.png", @@ -10,10 +10,11 @@ "crt_shader": "shaders/crt", "bell": "bell.wav", "crt_warp": 0.0, - "shell_command": "cmd.exe %userprofile%", + "shell_command": "cmd.exe %USERPROFILE%", "blink_interval": 300, "default_fg": 2, "default_bg": 2, + "maxlines": 1000, "color_scheme": [ diff --git a/src/resources/config/default_wsl.json b/src/resources/config/default_wsl.json index f770e8f..486c042 100644 --- a/src/resources/config/default_wsl.json +++ b/src/resources/config/default_wsl.json @@ -1,8 +1,8 @@ { "font": "font.png", - "font_width": 16, - "font_height": 32, - "font_scale": 0.8, + "font_width": 8, + "font_height": 16, + "font_scale": 1.2, "console_width": 120, "console_height": 30, "background": "crt.png", @@ -14,6 +14,7 @@ "blink_interval": 300, "default_fg": 6, "default_bg": 6, + "maxlines": 1000, "color_scheme": [ diff --git a/src/resources/default b/src/resources/default index d9f90ec..e897746 100644 --- a/src/resources/default +++ b/src/resources/default @@ -1 +1 @@ -config\default_wsl.json \ No newline at end of file +config\default_cmd.json \ No newline at end of file diff --git a/src/resources/font.png b/src/resources/font.png index 51ea10d..4e282ca 100644 Binary files a/src/resources/font.png and b/src/resources/font.png differ diff --git a/src/resources/imgui.ini b/src/resources/imgui.ini index c557cf3..ea4e0b0 100644 --- a/src/resources/imgui.ini +++ b/src/resources/imgui.ini @@ -45,7 +45,7 @@ Collapsed=0 [Window][##title] Pos=32,0 -Size=1552,32 +Size=1168,32 Collapsed=0 [Window][##XButton] @@ -54,7 +54,7 @@ Size=64,32 Collapsed=0 [Window][##Window_Buttons] -Pos=1456,0 +Pos=1072,0 Size=96,32 Collapsed=0