From 0d69d9ea575a29fd3f8a4117dd0488911a0a7410 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 11 Jun 2023 15:05:37 +0000 Subject: [PATCH] editor: add nec/nec_bold fonts This also adds a new "viewport" bit-field, which will be initially be used for incremental search data. Several redundant range checks were removed. --- Makefile | 8 +- editor/editor.hpp | 200 +++++++++++++++--------------- editor/main_saturn.cpp | 15 ++- editor/test_editor.cpp | 38 +++--- res/Bm437_NEC_MultiSpeed.otb | Bin 0 -> 8032 bytes res/Bm437_NEC_MultiSpeed_bold.otb | Bin 0 -> 8036 bytes 6 files changed, 135 insertions(+), 126 deletions(-) create mode 100644 res/Bm437_NEC_MultiSpeed.otb create mode 100644 res/Bm437_NEC_MultiSpeed_bold.otb diff --git a/Makefile b/Makefile index 407890d..1b11d99 100644 --- a/Makefile +++ b/Makefile @@ -94,9 +94,15 @@ scsp/sound_cpu__interrupt.elf: scsp/sound_cpu__interrupt.o m68k/interrupt.bin.o res/sperrypc.bitmap.bin: tools/ttf-bitmap ./tools/ttf-bitmap 20 7f res/Bm437_SperryPC_CGA.otb $@ +res/nec.bitmap.bin: tools/ttf-bitmap + ./tools/ttf-bitmap 20 7f res/Bm437_NEC_MultiSpeed.otb $@ + +res/nec_bold.bitmap.bin: tools/ttf-bitmap + ./tools/ttf-bitmap 20 7f res/Bm437_NEC_MultiSpeed_bold.otb $@ + editor/main_saturn.o: common/keyboard.hpp editor/editor.hpp -editor/main_saturn.elf: editor/main_saturn.o res/sperrypc.bitmap.bin.o sh/lib1funcs.o common/keyboard.o saturn/start.o +editor/main_saturn.elf: editor/main_saturn.o res/nec.bitmap.bin.o res/nec_bold.bitmap.bin.o sh/lib1funcs.o common/keyboard.o saturn/start.o # clean clean: clean-sh diff --git a/editor/editor.hpp b/editor/editor.hpp index d5922cd..4e98fdb 100644 --- a/editor/editor.hpp +++ b/editor/editor.hpp @@ -23,7 +23,7 @@ struct cursor { enum struct mode { normal, - mark + mark, }; struct selection { @@ -49,8 +49,11 @@ inline constexpr bool selection::contains(int32_t col, int32_t row) return false; } -template +template struct buffer { + static_assert((C & (C - 1)) == 0); + static_assert(C < 32 || C % 32 == 0); + line row[R]; line * lines[R]; int32_t length; @@ -64,6 +67,7 @@ struct buffer { int32_t cell_height; int32_t top; int32_t left; + int32_t viewport[V][C < 32 ? 1 : C / 32]; } window; struct cursor cursor; struct cursor mark; @@ -130,8 +134,8 @@ struct buffer { inline constexpr void scroll_new_col(const int32_t col); }; -template -inline constexpr buffer::buffer(int32_t width, int32_t height) +template +inline constexpr buffer::buffer(int32_t width, int32_t height) { this->length = 1; this->shadow.length = 1; @@ -148,14 +152,16 @@ inline constexpr buffer::buffer(int32_t width, int32_t height) this->lines[i] = nullptr; this->shadow.lines[i] = nullptr; + /* for (int32_t j = 0; j < C; j++) { this->row[i].buf[j] = 0x7f; } + */ } } -template -inline constexpr line * buffer::allocate() +template +inline constexpr line * buffer::allocate() { line * l; while ((l = &this->row[this->alloc_ix])->length != -1) { @@ -168,30 +174,29 @@ inline constexpr line * buffer::allocate() return l; } -template -inline constexpr void buffer::deallocate(line *& l) +template +inline constexpr void buffer::deallocate(line *& l) { // does not touch alloc_ix - fill(l->buf, 0x7f, l->length); l->length = -1; l->refcount = 0; l = nullptr; } -template -inline constexpr void buffer::decref(line *& l) +template +inline constexpr void buffer::decref(line *& l) { if (l == nullptr) return; else if (l->refcount == 1) - buffer::deallocate(l); + buffer::deallocate(l); else { l->refcount--; l = nullptr; } } -template -inline constexpr line * buffer::dup(line const * const src) +template +inline constexpr line * buffer::dup(line const * const src) { line * dst = this->allocate(); copy(&dst->buf[0], &src->buf[0], src->length); @@ -199,8 +204,8 @@ inline constexpr line * buffer::dup(line const * const src) return dst; } -template -inline constexpr line * buffer::mutref(line *& l) +template +inline constexpr line * buffer::mutref(line *& l) { if (l == nullptr) { l = this->allocate(); @@ -212,29 +217,29 @@ inline constexpr line * buffer::mutref(line *& l) return l; } -template -inline constexpr line * buffer::incref(line * l) +template +inline constexpr line * buffer::incref(line * l) { if (l != nullptr) l->refcount++; return l; } -template -inline constexpr int32_t buffer::line_length(line const * const l) +template +inline constexpr int32_t buffer::line_length(line const * const l) { if (l == nullptr) return 0; else return l->length; } -template -inline constexpr bool buffer::put(const uint8_t c) +template +inline constexpr bool buffer::put(const uint8_t c) { editor::cursor& cur = this->cursor; line * l = mutref(this->lines[cur.row]); // v // 0123 - if (l->length >= C || cur.col >= C || cur.col < 0) + if (cur.col >= C) return false; if (l->length > cur.col) { @@ -252,8 +257,8 @@ inline constexpr bool buffer::put(const uint8_t c) return true; } -template -inline constexpr bool buffer::delete_forward() +template +inline constexpr bool buffer::delete_forward() { if (this->mode == mode::mark) { this->mode = mode::normal; @@ -262,9 +267,6 @@ inline constexpr bool buffer::delete_forward() editor::cursor& cur = this->cursor; - if (cur.col < 0 || cur.col > C) - return false; - if (line_length(this->lines[cur.row]) == 0) { if (this->length == 1) return false; decref(this->lines[cur.row]); @@ -290,8 +292,8 @@ inline constexpr bool buffer::delete_forward() return true; } -template -inline constexpr bool buffer::delete_backward() +template +inline constexpr bool buffer::delete_backward() { if (this->mode == mode::mark) { this->mode = mode::normal; @@ -300,9 +302,6 @@ inline constexpr bool buffer::delete_backward() editor::cursor& cur = this->cursor; - if (cur.col < 0 || cur.col > C) - return false; - if (cur.col == 0) { if (cur.row == 0) return false; // make selection @@ -329,8 +328,8 @@ inline constexpr bool buffer::delete_backward() return true; } -template -inline constexpr void buffer::delete_word_forward() +template +inline constexpr void buffer::delete_word_forward() { mark_set(); cursor_scan_word_forward(); @@ -343,8 +342,8 @@ inline constexpr void buffer::delete_word_forward() this->mode = mode::normal; } -template -inline constexpr void buffer::delete_word_backward() +template +inline constexpr void buffer::delete_word_backward() { mark_set(); cursor_scan_word_backward(); @@ -357,8 +356,8 @@ inline constexpr void buffer::delete_word_backward() this->mode = mode::normal; } -template -inline constexpr bool buffer::cursor_left() +template +inline constexpr bool buffer::cursor_left() { editor::cursor& cur = this->cursor; @@ -380,8 +379,8 @@ inline constexpr bool buffer::cursor_left() return true; } -template -inline constexpr bool buffer::cursor_right() +template +inline constexpr bool buffer::cursor_right() { editor::cursor& cur = this->cursor; @@ -404,8 +403,8 @@ inline constexpr bool buffer::cursor_right() return true; } -template -inline constexpr bool buffer::cursor_up() +template +inline constexpr bool buffer::cursor_up() { editor::cursor& cur = this->cursor; @@ -421,8 +420,8 @@ inline constexpr bool buffer::cursor_up() return true; } -template -inline constexpr bool buffer::cursor_down() +template +inline constexpr bool buffer::cursor_down() { editor::cursor& cur = this->cursor; @@ -438,8 +437,8 @@ inline constexpr bool buffer::cursor_down() return true; } -template -inline constexpr bool buffer::cursor_home() +template +inline constexpr bool buffer::cursor_home() { editor::cursor& cur = this->cursor; cur.col = 0; @@ -447,8 +446,8 @@ inline constexpr bool buffer::cursor_home() return true; } -template -inline constexpr bool buffer::cursor_end() +template +inline constexpr bool buffer::cursor_end() { editor::cursor& cur = this->cursor; @@ -464,16 +463,16 @@ static inline constexpr bool word_boundary(int8_t c) || (c >= '0' && c <= '9')); } -template -inline constexpr uint8_t buffer::cursor_get(const editor::cursor& cur) +template +inline constexpr uint8_t buffer::cursor_get(const editor::cursor& cur) { return this->lines[cur.row] == nullptr ? 0 : (cur.col == this->lines[cur.row]->length ? '\n' : this->lines[cur.row]->buf[cur.col]); } -template -inline constexpr bool buffer::cursor_increment(editor::cursor& cur) +template +inline constexpr bool buffer::cursor_increment(editor::cursor& cur) { if (cur.col >= line_length(this->lines[cur.row])) { if (cur.row + 1 >= this->length) { @@ -488,8 +487,8 @@ inline constexpr bool buffer::cursor_increment(editor::cursor& cur) return true; } -template -inline constexpr void buffer::cursor_scan_word_forward() +template +inline constexpr void buffer::cursor_scan_word_forward() { // copy of this->cursor editor::cursor cur = this->cursor; @@ -508,8 +507,8 @@ inline constexpr void buffer::cursor_scan_word_forward() scroll_new_cursor(cur); } -template -inline constexpr bool buffer::cursor_decrement(editor::cursor& cur) +template +inline constexpr bool buffer::cursor_decrement(editor::cursor& cur) { if (cur.col == 0) { if (cur.row - 1 < 0) { @@ -524,8 +523,8 @@ inline constexpr bool buffer::cursor_decrement(editor::cursor& cur) return true; } -template -inline constexpr void buffer::cursor_scan_word_backward() +template +inline constexpr void buffer::cursor_scan_word_backward() { // copy of this->cursor editor::cursor cur = this->cursor; @@ -545,12 +544,12 @@ inline constexpr void buffer::cursor_scan_word_backward() scroll_new_cursor(cur); } -template -inline constexpr bool buffer::enter() +template +inline constexpr bool buffer::enter() { editor::cursor& cur = this->cursor; - if (cur.row >= R || cur.row < 0) + if (cur.row >= R) return false; if ((this->length - 1) > cur.row) { @@ -570,7 +569,6 @@ inline constexpr bool buffer::enter() old_l = mutref(old_l); old_l->length -= new_l->length; copy(&new_l->buf[0], &old_l->buf[cur.col], new_l->length); - fill(&old_l->buf[cur.col], 0x7f, new_l->length); } } else { // nothing to do, new_l->length is already 0 @@ -587,8 +585,8 @@ inline constexpr bool buffer::enter() return true; } -template -inline constexpr void buffer::line_kill() +template +inline constexpr void buffer::line_kill() { editor::cursor& cur = this->cursor; @@ -608,16 +606,16 @@ inline constexpr void buffer::line_kill() } } -template -inline constexpr void buffer::mark_set() +template +inline constexpr void buffer::mark_set() { this->mark.row = this->cursor.row; this->mark.col = this->cursor.col; this->mode = mode::mark; } -template -inline constexpr selection buffer::mark_get() +template +inline constexpr selection buffer::mark_get() { editor::cursor& cur = this->cursor; editor::cursor& mark = this->mark; @@ -643,8 +641,8 @@ inline constexpr selection buffer::mark_get() return sel; } -template -inline constexpr void buffer::delete_from_line(line *& l, +template +inline constexpr void buffer::delete_from_line(line *& l, const int32_t col_start_ix, const int32_t col_end_ix) { @@ -664,8 +662,8 @@ inline constexpr void buffer::delete_from_line(line *& l, } } -template -inline constexpr void buffer::selection_delete(const selection& sel) +template +inline constexpr void buffer::selection_delete(const selection& sel) { if (sel.min == sel.max) { return; @@ -720,8 +718,8 @@ inline constexpr void buffer::selection_delete(const selection& sel) } } -template -inline constexpr bool buffer::mark_delete() +template +inline constexpr bool buffer::mark_delete() { const selection sel = mark_get(); selection_delete(sel); @@ -732,14 +730,14 @@ inline constexpr bool buffer::mark_delete() return true; } -template -inline constexpr void buffer::quit() +template +inline constexpr void buffer::quit() { this->mode = mode::normal; } -template -inline constexpr void buffer::shadow_clear() +template +inline constexpr void buffer::shadow_clear() { for (int32_t i = 0; i < this->shadow.length; i++) decref(this->shadow.lines[i]); @@ -747,8 +745,8 @@ inline constexpr void buffer::shadow_clear() this->shadow.length = 1; } -template -inline constexpr void buffer::_shadow_cow(line * src, +template +inline constexpr void buffer::_shadow_cow(line * src, const int32_t dst_row_ix, const int32_t col_start_ix, const int32_t col_end_ix) @@ -765,8 +763,8 @@ inline constexpr void buffer::_shadow_cow(line * src, } } -template -inline constexpr bool buffer::shadow_copy() +template +inline constexpr bool buffer::shadow_copy() { if (this->mode != mode::mark) return false; @@ -812,8 +810,8 @@ inline constexpr bool buffer::shadow_copy() return true; } -template -inline constexpr bool buffer::shadow_cut() +template +inline constexpr bool buffer::shadow_cut() { if (this->mode != mode::mark) return false; @@ -826,8 +824,8 @@ inline constexpr bool buffer::shadow_cut() return true; } -template -inline constexpr void buffer::overwrite_line(line *& dst, +template +inline constexpr void buffer::overwrite_line(line *& dst, const int32_t dst_col, line * src, const int32_t src_col) @@ -853,8 +851,8 @@ inline constexpr void buffer::overwrite_line(line *& dst, } } -template -inline constexpr bool buffer::shadow_paste() +template +inline constexpr bool buffer::shadow_paste() { if (this->mode == mode::mark) this->mode = mode::normal; @@ -936,15 +934,15 @@ inline constexpr bool buffer::shadow_paste() return true; } -template -inline constexpr void buffer::scroll_up() +template +inline constexpr void buffer::scroll_up() { if (this->cursor.row < this->window.top) this->window.top = this->cursor.row; } -template -inline constexpr void buffer::scroll_down() +template +inline constexpr void buffer::scroll_down() { // 0: a - // 1: bv - @@ -957,15 +955,15 @@ inline constexpr void buffer::scroll_down() this->window.top = (this->cursor.row - (this->window.cell_height - 1)); } -template -inline constexpr void buffer::scroll_left() +template +inline constexpr void buffer::scroll_left() { if (this->cursor.col < this->window.left) this->window.left = this->cursor.col; } -template -inline constexpr void buffer::scroll_right() +template +inline constexpr void buffer::scroll_right() { // 0: a - // 1: bv - @@ -978,8 +976,8 @@ inline constexpr void buffer::scroll_right() this->window.left = (this->cursor.col - (this->window.cell_width - 1)); } -template -inline constexpr void buffer::scroll_new_cursor(const editor::cursor& oth) +template +inline constexpr void buffer::scroll_new_cursor(const editor::cursor& oth) { editor::cursor& cur = this->cursor; @@ -990,8 +988,8 @@ inline constexpr void buffer::scroll_new_cursor(const editor::cursor& oth) else { cur.col = oth.col; scroll_left(); } } -template -inline constexpr void buffer::scroll_new_col(const int32_t col) +template +inline constexpr void buffer::scroll_new_col(const int32_t col) { editor::cursor& cur = this->cursor; diff --git a/editor/main_saturn.cpp b/editor/main_saturn.cpp index aae7f71..05956bf 100644 --- a/editor/main_saturn.cpp +++ b/editor/main_saturn.cpp @@ -12,9 +12,10 @@ #include "editor.hpp" -extern void * _sperrypc_bitmap_start __asm("_binary_res_sperrypc_bitmap_bin_start"); +extern void * _nec_bitmap_start __asm("_binary_res_nec_bitmap_bin_start"); +extern void * _nec_bold_bitmap_start __asm("_binary_res_nec_bold_bitmap_bin_start"); -using buffer_type = editor::buffer<64, 64>; +using buffer_type = editor::buffer<64, 64, 40>; constexpr int32_t viewport_max_col = 320 / 8; constexpr int32_t viewport_max_row = 240 / 8; @@ -62,12 +63,16 @@ namespace pix_fmt_4bpp void cell_data() { - const uint8_t * buf = reinterpret_cast(&_sperrypc_bitmap_start); + const uint8_t * normal = reinterpret_cast(&_nec_bitmap_start); + const uint8_t * bold = reinterpret_cast(&_nec_bold_bitmap_start); for (int ix = 0; ix <= (0x7f - 0x20); ix++) { for (int y = 0; y < 8; y++) { - uint8_t row = buf[ix * 8 + y]; - vdp2.vram.u32[(ix * 8) + y] = pix_fmt_4bpp::bits(row); + const uint8_t row_n = normal[ix * 8 + y]; + vdp2.vram.u32[ 0 + (ix * 8) + y] = pix_fmt_4bpp::bits(row_n); + + const uint8_t row_b = bold[ix * 8 + y]; + vdp2.vram.u32[96 + (ix * 8) + y] = pix_fmt_4bpp::bits(row_b); } } } diff --git a/editor/test_editor.cpp b/editor/test_editor.cpp index 28b2701..60e5a5c 100644 --- a/editor/test_editor.cpp +++ b/editor/test_editor.cpp @@ -7,7 +7,7 @@ using namespace editor; static void test_allocate() { - buffer<8, 4> b {4, 2}; + buffer<8, 4, 4> b {4, 2}; decltype(b)::line_type * l; assert(b.row[0].length == -1); @@ -62,7 +62,7 @@ static void test_put() { // v // "as" -> "abs" - buffer<8, 4> b {4, 2}; + buffer<8, 4, 4> b {4, 2}; decltype(b)::line_type * l; assert(b.cursor.col == 0); @@ -101,7 +101,7 @@ static void test_put() void test_backspace() { - buffer<8, 4> b {4, 2}; + buffer<8, 4, 4> b {4, 2}; decltype(b)::line_type * l; b.put('a'); @@ -137,7 +137,7 @@ void test_enter() // [0] as // [1] Df // [2] qwer - buffer<8, 4> b {4, 2}; + buffer<8, 4, 4> b {4, 2}; b.cursor.row = 0; b.cursor.col = 0; @@ -191,7 +191,7 @@ void test_enter_backspace1() // ab // cd - buffer<8, 4> b {4, 2}; + buffer<8, 4, 4> b {4, 2}; b.put('a'); b.put('b'); @@ -216,7 +216,7 @@ void test_enter_backspace1() void test_enter_backspace2() { - buffer<8, 4> b {4, 2}; + buffer<8, 4, 4> b {4, 2}; b.put('a'); b.enter(); @@ -231,7 +231,7 @@ void test_enter_backspace2() void test_enter_scroll() { - buffer<8, 4> b {4, 2}; + buffer<8, 4, 4> b {4, 2}; assert(b.window.top == 0); b.put('a'); @@ -253,7 +253,7 @@ void test_enter_scroll() void test_first_enter() { - buffer<8, 4> b {4, 2}; + buffer<8, 4, 4> b {4, 2}; b.enter(); assert(b.length == 2); @@ -266,7 +266,7 @@ void test_enter_backspace3() // // b - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; b.put('a'); b.enter(); @@ -303,7 +303,7 @@ void test_copy() // qwer // j - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; b.put('a'); b.put('s'); @@ -357,7 +357,7 @@ void test_copy() void test_copy_same_line() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; // v // asdF @@ -394,7 +394,7 @@ void test_copy_same_line() void test_copy_multi_line_cow() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; // v // asdF @@ -422,7 +422,7 @@ void test_copy_multi_line_cow() void test_copy_multi_line_offset() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; b.put('a'); b.put('s'); @@ -477,7 +477,7 @@ void test_copy_multi_line_offset() void test_delete_from_line() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; b.put('a'); b.put('s'); @@ -499,7 +499,7 @@ void test_delete_from_line() void test_selection_delete() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; b.put('s'); b.put('p'); @@ -563,7 +563,7 @@ void test_selection_delete() void test_shadow_paste_oneline() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; b.put('q'); b.put('w'); @@ -636,7 +636,7 @@ void test_shadow_paste_oneline() void test_shadow_paste_multiline() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; // (qw // er @@ -733,7 +733,7 @@ void test_shadow_paste_multiline() void test_delete_forward() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; b.put('a'); b.put('b'); b.put('c'); @@ -765,7 +765,7 @@ void test_delete_forward() void test_delete_word_backward() { - buffer<8, 8> b {4, 2}; + buffer<8, 8, 8> b {4, 2}; b.put('q'); b.put('w'); diff --git a/res/Bm437_NEC_MultiSpeed.otb b/res/Bm437_NEC_MultiSpeed.otb new file mode 100644 index 0000000000000000000000000000000000000000..4e59d456c688ef78243fbacc629417791b4aa3ff GIT binary patch literal 8032 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 A2mk;8 literal 0 HcmV?d00001 diff --git a/res/Bm437_NEC_MultiSpeed_bold.otb b/res/Bm437_NEC_MultiSpeed_bold.otb new file mode 100644 index 0000000000000000000000000000000000000000..5eae61466b8f7c0bf82c5856523f292ff1dc882d GIT binary patch literal 8036 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 dd4I9)Io3Ty4efsg_F literal 0 HcmV?d00001