add basic terminal

This commit is contained in:
Zihao Yu 2024-01-04 01:35:59 +08:00
parent 7d5900e5ea
commit f4d22b5b16
6 changed files with 147 additions and 43 deletions

26
include/term.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _NVBOARD_TERM_H
#define _NVBOARD_TERM_H
class Term {
private:
SDL_Renderer *renderer;
SDL_Rect region;
int w_in_char, h_in_char;
std::vector<uint8_t *> lines;
int cursor_x, cursor_y;
SDL_Texture *cursor_texture;
int screen_y;
void clear_screen();
uint8_t *new_line();
void draw_cursor();
public:
Term(SDL_Renderer *r, int x, int y, int w, int h);
~Term();
void feed_ch(uint8_t ch);
void update_gui();
};
#endif

View File

@ -2,14 +2,13 @@
#define _NVBOARD_UART_H
#include <component.h>
#include <string>
#include <term.h>
class UART : public Component{
private:
int region_w, region_h;
std::string str;
Term *term;
public:
UART(SDL_Renderer *rend, int cnt, int init_val, int ct);
UART(SDL_Renderer *rend, int cnt, int init_val, int ct, int x, int y, int w, int h);
~UART();
virtual void update_gui();

View File

@ -1,29 +1,41 @@
#include <nvboard.h>
#include <SDL_ttf.h>
static TTF_Font *font = NULL;
static SDL_Texture* font[128] = { NULL };
void init_font() {
void init_font(SDL_Renderer *renderer) {
int ret = TTF_Init();
assert(ret != -1);
std::string nvboard_home = getenv("NVBOARD_HOME");
font = TTF_OpenFont((nvboard_home + "/resources/font/" + "FreeMono.ttf").c_str(), 16);
assert(font != NULL);
TTF_Font *f = TTF_OpenFont((nvboard_home + "/resources/font/" + "FreeMono.ttf").c_str(), 16);
assert(f != NULL);
TTF_SetFontHinting(f, TTF_HINTING_MONO);
TTF_SetFontStyle(f, TTF_STYLE_BOLD);
SDL_Color c = {.r = 0x00, .g = 0x00, .b = 0x00 };
for (int i = 1; i < 128; i ++) {
SDL_Surface *s = TTF_RenderGlyph_Solid(f, i, c);
if (s == NULL) {
printf("error = %s\n", SDL_GetError());
}
assert(s != NULL);
assert(s->w == 10);
assert(s->h == 16);
SDL_Texture *t = SDL_CreateTextureFromSurface(renderer, s);
assert(t != NULL);
font[i] = t;
SDL_FreeSurface(s);
}
TTF_CloseFont(f);
}
SDL_Texture* render_str(SDL_Renderer *renderer, std::string str, int wrap_len_in_pixel, int *w, int *h) {
SDL_Color c = {.r = 0x00, .g = 0x00, .b = 0x00 };
SDL_Surface *s = TTF_RenderText_Solid_Wrapped(font, str.c_str(), c, wrap_len_in_pixel);
assert(s != NULL);
SDL_Texture *t = SDL_CreateTextureFromSurface(renderer, s);
assert(t != NULL);
*w = s->w; *h = s->h;
SDL_FreeSurface(s);
return t;
SDL_Texture* get_font_texture(uint8_t ch) {
assert(ch < 128);
return font[ch == 0 ? ' ' : ch];
}
void close_font() {
TTF_CloseFont(font);
font = NULL;
TTF_Quit();
}

View File

@ -79,9 +79,8 @@ void nvboard_init(int vga_clk_cycle) {
);
SDL_SetRenderDrawColor(main_renderer, 0xff, 0xff, 0xff, 0);
void init_font();
init_font();
void init_font(SDL_Renderer *renderer);
init_font(main_renderer);
init_render(main_renderer);
init_components(main_renderer);
init_gui(main_renderer);

78
src/term.cpp Normal file
View File

@ -0,0 +1,78 @@
#include <nvboard.h>
#include <term.h>
SDL_Texture* get_font_texture(uint8_t ch);
Term::Term(SDL_Renderer *r, int x, int y, int w, int h):
renderer(r), cursor_x(0), cursor_y(0), screen_y(0) {
region = { .x = x, .y = y, .w = w, .h = h };
w_in_char = region.w / 10;
h_in_char = region.h / 16;
uint8_t *l = new_line();
memset(l, 'a', w_in_char);
cursor_texture = new_texture(r, 10, 16, 0x10, 0x10, 0x10);
}
Term::~Term() {
SDL_DestroyTexture(cursor_texture);
}
void Term::clear_screen() {
SDL_RenderFillRect(renderer, &region);
}
uint8_t* Term::new_line() {
uint8_t *l = new uint8_t[w_in_char];
memset(l, ' ', w_in_char);
lines.push_back(l);
return l;
}
void Term::feed_ch(uint8_t ch) {
assert(ch < 128);
int y = cursor_y;
assert(y < lines.size());
uint8_t *l = lines[y];
l[cursor_x] = ch;
cursor_x ++;
if (cursor_x == w_in_char) {
cursor_x = 0;
cursor_y ++;
if (cursor_y >= lines.size()) new_line();
if (cursor_y == screen_y + h_in_char) screen_y ++; // scroll one line
}
}
void Term::draw_cursor() {
if (cursor_y >= screen_y && cursor_y < screen_y + h_in_char) {
int y = cursor_y - screen_y;
int x = cursor_x;
SDL_Rect rect = region;
rect.w = 10, rect.h = 16;
rect.y += 16 * y;
rect.x += 10 * x;
SDL_RenderCopy(renderer, cursor_texture, NULL, &rect);
}
}
void Term::update_gui() {
clear_screen();
SDL_Rect rect = region;
int x_start = rect.x;
rect.w = 10, rect.h = 16;
for (int y = 0; y < h_in_char; y ++) {
if (screen_y + y >= lines.size()) break;
uint8_t *l = lines[screen_y + y];
for (int x = 0; x < w_in_char; x ++) {
uint8_t ch = l[x];
SDL_Texture *t = get_font_texture(ch);
SDL_RenderCopy(renderer, t, NULL, &rect);
rect.x += 10;
}
rect.x = x_start;
rect.y += 16;
}
draw_cursor();
set_redraw();
}

View File

@ -3,14 +3,9 @@
UART* uart = NULL;
SDL_Texture* render_str(SDL_Renderer *renderer, std::string str, int wrap_len_in_pixel, int *w, int *h);
UART::UART(SDL_Renderer *rend, int cnt, int init_val, int ct):
Component(rend, cnt, init_val, ct),
region_w(WINDOW_WIDTH / 2), region_h(WINDOW_HEIGHT / 2), str(" ") {
SDL_Texture *temp_texture = SDL_CreateTexture(rend, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, region_w, region_h);
set_texture(temp_texture, 0);
UART::UART(SDL_Renderer *rend, int cnt, int init_val, int ct, int x, int y, int w, int h):
Component(rend, cnt, init_val, ct) {
term = new Term(rend, x, y, w, h);
}
UART::~UART() {
@ -18,15 +13,7 @@ UART::~UART() {
}
void UART::update_gui() {
SDL_Renderer *r = get_renderer();
SDL_Rect rect = *get_rect(0);
SDL_RenderFillRect(r, &rect);
int w = 0, h = 0;
SDL_Texture *t = render_str(r, str, region_w, &w, &h);
rect.w = w; rect.h = h;
SDL_RenderCopy(r, t, NULL, &rect);
SDL_DestroyTexture(t);
set_redraw();
term->update_gui();
}
void UART::update_state() {
@ -34,15 +21,18 @@ void UART::update_state() {
i ++;
if (i < 10) return;
i = 0;
char last = str[str.length() - 1];
str += last + 1;
static uint8_t ch = ' ';
ch += 1;
if (ch == 128) ch = ' ';
term->feed_ch(ch);
update_gui();
}
void init_uart(SDL_Renderer *renderer) {
uart = new UART(renderer, 1, 0, UART_TYPE);
int x = WINDOW_WIDTH / 2, y = 0, w = WINDOW_WIDTH / 2, h = WINDOW_HEIGHT / 2;
uart = new UART(renderer, 1, 0, UART_TYPE, x, y, w, h);
SDL_Rect *rect_ptr = new SDL_Rect;
*rect_ptr = (SDL_Rect){WINDOW_WIDTH / 2, 0, WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
*rect_ptr = (SDL_Rect){x, y, w, h};
uart->set_rect(rect_ptr, 0);
uart->add_pin(UART_TX);
uart->add_pin(UART_RX);