mirror of
https://github.com/Jimmy-Z/term256.git
synced 2025-06-18 16:55:43 -04:00
works but slow
This commit is contained in:
commit
5cf3c1ada5
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.vs
|
||||
build
|
||||
*.elf
|
||||
*.nds
|
||||
*.sln
|
||||
*.vcxproj*
|
138
Makefile
Normal file
138
Makefile
Normal file
@ -0,0 +1,138 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/ds_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# INCLUDES is a list of directories containing extra header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(shell basename $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
DATA :=
|
||||
INCLUDES := include
|
||||
GRAPHICS := data
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -mthumb -mthumb-interwork
|
||||
|
||||
CFLAGS := -g -Wall -O2\
|
||||
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer\
|
||||
-ffast-math \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM9
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with the project
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -lnds9
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(LIBNDS)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(PNGFILES:.png=.o) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
.PHONY: $(BUILD) clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(TARGET).ds.gba
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT).nds : $(OUTPUT).elf
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.s %.h : %.png %.grit
|
||||
#---------------------------------------------------------------------------------
|
||||
grit $< -fts -o$*
|
||||
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
7
source/font.h
Normal file
7
source/font.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define FONT_WIDTH 6
|
||||
#define FONT_HEIGHT 10
|
||||
|
||||
extern const unsigned char font[];
|
||||
|
3079
source/font_6x10.c
Normal file
3079
source/font_6x10.c
Normal file
File diff suppressed because it is too large
Load Diff
114
source/main.c
Normal file
114
source/main.c
Normal file
@ -0,0 +1,114 @@
|
||||
#include <nds.h>
|
||||
|
||||
#include "term256.h"
|
||||
#include "term256ext.h"
|
||||
|
||||
// show ANSI color palette, 8 rows
|
||||
void show_ansi256_color_table(u16 *fb, unsigned width, unsigned height) {
|
||||
// 4 pixels at a time, there might be some overlaps, but we don't care
|
||||
width >>= 1;
|
||||
unsigned row_height = height / 8;
|
||||
// first row, 16 standard and intense colors
|
||||
unsigned block_width = width / 16;
|
||||
for (unsigned i = 0; i < 16; ++i) {
|
||||
u16 c2 = i | (i << 8);
|
||||
unsigned start_x = i * block_width;
|
||||
for (unsigned y = 0; y < row_height; ++y) {
|
||||
for (unsigned x = start_x; x < start_x + block_width; ++x){
|
||||
fb[y * width + x] = c2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// six rows, 6x6x6 RGB colors
|
||||
block_width = width / 36;
|
||||
for (unsigned i = 0; i < 6; ++i) {
|
||||
for (unsigned j = 0; j < 36; ++j) {
|
||||
unsigned c = 16 + i * 36 + j;
|
||||
u16 c2 = c | (c << 8);
|
||||
unsigned start_x = j * block_width;
|
||||
unsigned start_y = (i + 1) * row_height;
|
||||
for (unsigned y = start_y; y < start_y + row_height; ++y) {
|
||||
for (unsigned x = start_x; x < start_x + block_width; ++x){
|
||||
fb[y * width + x] = c2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// final row, 24 grayscales
|
||||
block_width = width / 24;
|
||||
for (unsigned i = 0; i < 24; ++i) {
|
||||
unsigned c = 232 + i;
|
||||
u32 c2 = c | (c << 8);
|
||||
unsigned start_x = i * block_width;
|
||||
for (unsigned y = row_height * 7; y < height; ++y) {
|
||||
for (unsigned x = start_x; x < start_x + block_width; ++x){
|
||||
fb[y * width + x] = c2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned wait_key(unsigned wanted) {
|
||||
while (1) {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
unsigned keys = keysDown();
|
||||
if (keys & wanted) {
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
term_t t0, t1;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
videoSetModeSub(MODE_3_2D);
|
||||
vramSetBankC(VRAM_C_SUB_BG);
|
||||
u16 *fb0 = bgGetGfxPtr(bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 0, 0));
|
||||
generate_ansi256_palette(BG_PALETTE_SUB);
|
||||
term_init(&t0, fb0);
|
||||
select_term(&t0);
|
||||
iprtf("This an experimental 256 color terminal emulator\n"
|
||||
"\tWidth:\t%u\n\tHeight:\t%u\n\tChars:\t%u\n"
|
||||
" \n"
|
||||
"press A to loop, B to quit",
|
||||
TERM_WIDTH, TERM_HEIGHT, TERM_BUF_LEN);
|
||||
|
||||
videoSetMode(MODE_3_2D);
|
||||
vramSetBankA(VRAM_A_MAIN_BG);
|
||||
u16 *fb1 = bgGetGfxPtr(bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 0, 0));
|
||||
dmaCopy(BG_PALETTE_SUB, BG_PALETTE, 256 * 2);
|
||||
term_init(&t1, fb1);
|
||||
select_term(&t1);
|
||||
|
||||
// scroll test
|
||||
while (true) {
|
||||
if (wait_key(KEY_A | KEY_B) == KEY_B) {
|
||||
break;
|
||||
}
|
||||
for (unsigned i = 0; i < 16; ++i) {
|
||||
iprtf("%x\n", i);
|
||||
}
|
||||
prt("...\rcarriage return test\n");
|
||||
// color test
|
||||
for (unsigned i = 0; i < 256; ++i) {
|
||||
term_ctl(&t1, TERM_COLOR, i);
|
||||
iprtf("%02x", i);
|
||||
}
|
||||
// color and font face test
|
||||
term_ctl(&t1, TERM_COLOR, 15);
|
||||
term_ctl(&t1, TERM_BG_COLOR, 0);
|
||||
prt("\na quick brown fox jumps over the lazy dog,\n");
|
||||
term_ctl(&t1, TERM_COLOR, 0);
|
||||
term_ctl(&t1, TERM_BG_COLOR, 15);
|
||||
prt("A QUICK BROWN FOX JUMPS OVER THE LAZY DOG.\n");
|
||||
|
||||
if (wait_key(KEY_A | KEY_B) == KEY_B) {
|
||||
break;
|
||||
}
|
||||
show_ansi256_color_table(fb1, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
228
source/term256.c
Normal file
228
source/term256.c
Normal file
@ -0,0 +1,228 @@
|
||||
#include <nds.h>
|
||||
#include <assert.h>
|
||||
#include "term256.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ITCM_CODE
|
||||
#define UNROLL
|
||||
#else
|
||||
#define UNROLL __attribute__((optimize("unroll-loops")))
|
||||
#endif
|
||||
|
||||
#define RGB(r,g,b) RGB15(r, g, b)
|
||||
#define RBITS 5
|
||||
#define RMAX (1 << RBITS)
|
||||
#define GBITS 5
|
||||
#define GMAX (1 << GBITS)
|
||||
#define BBITS 5
|
||||
#define BMAX (1 << BBITS)
|
||||
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
|
||||
void generate_ansi256_palette(color_t *p) {
|
||||
// maybe I should use round to improve precision
|
||||
// standard colors
|
||||
*p++ = RGB(0, 0, 0);
|
||||
*p++ = RGB(RMAX >> 1, 0, 0);
|
||||
*p++ = RGB(0, GMAX >> 1, 0);
|
||||
*p++ = RGB(RMAX >> 1, GMAX >> 1, 0);
|
||||
*p++ = RGB(0, 0, BMAX >> 1);
|
||||
*p++ = RGB(RMAX >> 1, 0, BMAX >> 1);
|
||||
*p++ = RGB(0, GMAX >> 1, BMAX >> 1);
|
||||
*p++ = RGB((RMAX * 3) >> 2, (GMAX * 3) >> 2, (BMAX * 3) >> 2);
|
||||
// high-intensity colors
|
||||
*p++ = RGB(RMAX >> 1, GMAX >> 1, BMAX >> 1);
|
||||
*p++ = RGB(RMAX - 1, 0, 0);
|
||||
*p++ = RGB(0, GMAX - 1, 0);
|
||||
*p++ = RGB(RMAX - 1, GMAX - 1, 0);
|
||||
*p++ = RGB(0, 0, BMAX - 1);
|
||||
*p++ = RGB(RMAX - 1, 0, BMAX - 1);
|
||||
*p++ = RGB(0, GMAX - 1, BMAX - 1);
|
||||
*p++ = RGB(RMAX - 1, GMAX - 1, BMAX - 1);
|
||||
// 216 colors, 6 * 6 * 6
|
||||
unsigned rsteps[6] = { 0, (RMAX - 1) / 5, (RMAX - 1) * 2 / 5,
|
||||
(RMAX - 1) * 3 / 5, (RMAX - 1) * 4 / 5, RMAX - 1 };
|
||||
unsigned gsteps[6] = { 0, (GMAX - 1) / 5, (GMAX - 1) * 2 / 5,
|
||||
(GMAX - 1) * 3 / 5, (GMAX - 1) * 4 / 5, GMAX - 1 };
|
||||
unsigned bsteps[6] = { 0, (BMAX - 1) / 5, (BMAX - 1) * 2 / 5,
|
||||
(BMAX - 1) * 3 / 5, (BMAX - 1) * 4 / 5, BMAX - 1 };
|
||||
// how do I tell gcc not to unroll this?
|
||||
for (unsigned r = 0; r < 6; ++r) {
|
||||
for (unsigned g = 0; g < 6; ++g) {
|
||||
for (unsigned b = 0; b < 6; ++b) {
|
||||
*p++ = RGB(rsteps[r], gsteps[g], bsteps[b]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 24 gray scales, not including full white and full black, so 25 steps
|
||||
for (unsigned j = 1; j < 25; ++j) {
|
||||
*p++ = RGB((RMAX - 1) * j / 25, (GMAX - 1) * j / 25, (BMAX - 1) * j / 25);
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(FONT_WIDTH == 6, "this thing can only handle FONT_WIDTH == 6");
|
||||
|
||||
#ifdef ARM9
|
||||
ITCM_CODE
|
||||
#endif
|
||||
UNROLL
|
||||
static inline void write_char(u16 *fb, unsigned x, unsigned y, unsigned char c, unsigned char color, unsigned char bg_color) {
|
||||
const unsigned char *g = &font[c * FONT_HEIGHT];
|
||||
for (unsigned fy = 0; fy < FONT_HEIGHT; ++fy) {
|
||||
unsigned char l = g[fy]; // line fy of the glyph
|
||||
u16 *p = &fb[((y + fy) * SCREEN_WIDTH + x) / 2];
|
||||
*p++ = (l & 0x80 ? color : bg_color) | ((l & 0x40 ? color : bg_color) << 8);
|
||||
*p++ = (l & 0x20 ? color : bg_color) | ((l & 0x10 ? color : bg_color) << 8);
|
||||
*p = (l & 0x08 ? color : bg_color) | ((l & 0x04 ? color : bg_color) << 8);
|
||||
}
|
||||
}
|
||||
|
||||
void term_rst(term_t *t, u8 fg, u8 bg) {
|
||||
/* so memset just fail?
|
||||
memset(t->c, 0, sizeof(TERM_BUF_LEN));
|
||||
memset(t->fg, fg, sizeof(TERM_BUF_LEN));
|
||||
memset(t->bg, bg, sizeof(TERM_BUF_LEN));
|
||||
for (unsigned i = 0; i < TERM_BUF_LEN; ++i) {
|
||||
if (t->fg[i] != fg) {
|
||||
iprintf("fg[%u] == %u\n", i, t->fg[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
for (unsigned i = 0; i < TERM_BUF_LEN; ++i) {
|
||||
t->c[i] = 0;
|
||||
t->fg[i] = fg;
|
||||
t->bg[i] = bg;
|
||||
}
|
||||
t->cur = 0;
|
||||
t->cur_fg = fg;
|
||||
t->cur_bg = bg;
|
||||
t->update_region_a = 0;
|
||||
t->update_region_b = 0;
|
||||
t->needs_full_update = 0;
|
||||
}
|
||||
|
||||
void term_init(term_t *t, u16 *fb) {
|
||||
t->fb = fb;
|
||||
term_rst(t, 15, 0);
|
||||
}
|
||||
|
||||
// void wait_key(unsigned key);
|
||||
|
||||
#ifdef ARM9
|
||||
ITCM_CODE
|
||||
#endif
|
||||
void term_update_fb(term_t *t) {
|
||||
if (t->needs_full_update) {
|
||||
unsigned offset = 0;
|
||||
unsigned y = 0;
|
||||
for (unsigned ty = 0; ty < TERM_HEIGHT; ++ty) {
|
||||
unsigned x = 0;
|
||||
for (unsigned tx = 0; tx < TERM_WIDTH; ++tx) {
|
||||
// wait_key(KEY_A);
|
||||
// iprintf("%u,%c,%u,%u,%u,%u,%u,%u\n", offset, t->c[offset], t->fg[offset], t->bg[offset], ty, tx, y, x);
|
||||
write_char(t->fb, x, y, t->c[offset], t->fg[offset], t->bg[offset]);
|
||||
x += FONT_WIDTH;
|
||||
++offset;
|
||||
}
|
||||
y += FONT_HEIGHT;
|
||||
}
|
||||
t->needs_full_update = 0;
|
||||
t->update_region_a = t->update_region_b = t->cur;
|
||||
} else if (t->update_region_a < t->update_region_b) {
|
||||
// TODO: partial updates
|
||||
}
|
||||
}
|
||||
|
||||
void scroll(term_t *t) {
|
||||
unsigned i;
|
||||
u8 *p0 = t->c, *p0s = p0 + TERM_WIDTH;
|
||||
u8 *p1 = t->fg, *p1s = p1 + TERM_WIDTH;
|
||||
u8 *p2 = t->bg, *p2s = p2 + TERM_WIDTH;
|
||||
for (i = 0; i < TERM_BUF_LEN - TERM_WIDTH; ++i){
|
||||
*p0++ = *p0s++;
|
||||
*p1++ = *p1s++;
|
||||
*p2++ = *p2s++;
|
||||
}
|
||||
// fill the new line with cursor fg/bg
|
||||
for (i = 0; i < TERM_WIDTH; ++i) {
|
||||
*p0++ = 0;
|
||||
*p1++ = t->cur_fg;
|
||||
*p2++ = t->cur_bg;
|
||||
}
|
||||
t->cur -= TERM_WIDTH;
|
||||
}
|
||||
|
||||
void term_ctl(term_t *t, int ctl_code, int ctl_param) {
|
||||
switch (ctl_code) {
|
||||
case TERM_COLOR:
|
||||
t->cur_fg = ctl_param;
|
||||
break;
|
||||
case TERM_BG_COLOR:
|
||||
t->cur_bg = ctl_param;
|
||||
break;
|
||||
case TERM_MOVE_X: {
|
||||
unsigned x_pos = t->cur % TERM_WIDTH;
|
||||
unsigned min_cur = t->cur - x_pos;
|
||||
unsigned max_cur = t->cur - x_pos + TERM_WIDTH - 1;
|
||||
t->cur += ctl_param;
|
||||
if (t->cur < min_cur) {
|
||||
t->cur = min_cur;
|
||||
} else if(t->cur > max_cur){
|
||||
t->cur = max_cur;
|
||||
}
|
||||
break;
|
||||
} case TERM_MOVE_Y: {
|
||||
unsigned min_cur = t->cur % TERM_WIDTH;
|
||||
unsigned max_cur = TERM_WIDTH * (TERM_HEIGHT - 1) + min_cur;
|
||||
t->cur += ctl_param * TERM_HEIGHT;
|
||||
if (t->cur < min_cur) {
|
||||
t->cur = min_cur;
|
||||
} else if(t->cur > max_cur){
|
||||
t->cur = max_cur;
|
||||
}
|
||||
break;
|
||||
} default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define TAB_WIDTH 4
|
||||
|
||||
void term_prt(term_t * t, const char *s) {
|
||||
// I'm too lazy to parse ANSI escape code
|
||||
// use term_ctl instead
|
||||
unsigned char c;
|
||||
while ((c = *(const unsigned char*)s) != 0) {
|
||||
if (c == '\n') {
|
||||
unsigned tx = t->cur % TERM_WIDTH;
|
||||
if (tx != 0) {
|
||||
// do not allow empty line
|
||||
// also, new line never causes scroll
|
||||
t->cur += TERM_WIDTH - tx;
|
||||
}
|
||||
} else if (c == '\r') {
|
||||
t->cur -= t->cur % TERM_WIDTH;
|
||||
} else if (c == '\t') {
|
||||
unsigned tx = t->cur % TERM_WIDTH;
|
||||
unsigned new_tx = tx + TAB_WIDTH;
|
||||
new_tx -= new_tx % TAB_WIDTH;
|
||||
if (new_tx > TERM_WIDTH) {
|
||||
new_tx = TERM_WIDTH;
|
||||
}
|
||||
t->cur += new_tx - tx;
|
||||
} else {
|
||||
if (t->cur == TERM_BUF_LEN) {
|
||||
scroll(t);
|
||||
}
|
||||
t->c[t->cur] = c;
|
||||
t->fg[t->cur] = t->cur_fg;
|
||||
t->bg[t->cur] = t->cur_bg;
|
||||
++t->cur;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
// TODO: partial updates
|
||||
t->needs_full_update = 1;
|
||||
term_update_fb(t);
|
||||
}
|
||||
|
38
source/term256.h
Normal file
38
source/term256.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <nds.h>
|
||||
#include "font.h"
|
||||
|
||||
#define TERM_WIDTH (SCREEN_WIDTH / FONT_WIDTH)
|
||||
#define TERM_HEIGHT (SCREEN_HEIGHT / FONT_HEIGHT)
|
||||
#define TERM_BUF_LEN (TERM_WIDTH * TERM_HEIGHT)
|
||||
|
||||
typedef u16 color_t;
|
||||
|
||||
void generate_ansi256_palette(color_t *p);
|
||||
|
||||
typedef struct {
|
||||
u16 *fb;
|
||||
u8 c[TERM_BUF_LEN];
|
||||
u8 fg[TERM_BUF_LEN];
|
||||
u8 bg[TERM_BUF_LEN];
|
||||
unsigned cur;
|
||||
u8 cur_fg;
|
||||
u8 cur_bg;
|
||||
unsigned update_region_a;
|
||||
unsigned update_region_b;
|
||||
int needs_full_update;
|
||||
}term_t;
|
||||
|
||||
enum {
|
||||
TERM_COLOR,
|
||||
TERM_BG_COLOR,
|
||||
TERM_MOVE_X,
|
||||
TERM_MOVE_Y,
|
||||
};
|
||||
|
||||
void term_init(term_t *t, u16 *fb);
|
||||
|
||||
void term_prt(term_t * t, const char *string);
|
||||
|
||||
void term_ctl(term_t *t, int ctl_code, int ctl_param);
|
34
source/term256ext.c
Normal file
34
source/term256ext.c
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "term256.h"
|
||||
|
||||
static term_t *current_term;
|
||||
|
||||
void select_term(term_t *t) {
|
||||
current_term = t;
|
||||
}
|
||||
|
||||
// do not print too long
|
||||
#define STR_BUF_LEN 0x200
|
||||
char str_buf[STR_BUF_LEN];
|
||||
|
||||
void iprtf(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsniprintf(str_buf, STR_BUF_LEN, fmt, args);
|
||||
va_end(args);
|
||||
term_prt(current_term, str_buf);
|
||||
}
|
||||
|
||||
void prtf(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(str_buf, STR_BUF_LEN, fmt, args);
|
||||
va_end(args);
|
||||
term_prt(current_term, str_buf);
|
||||
}
|
||||
|
||||
void prt(const char *s) {
|
||||
term_prt(current_term, s);
|
||||
}
|
7
source/term256ext.h
Normal file
7
source/term256ext.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
void select_term(term_t *t);
|
||||
|
||||
void iprtf(const char *fmt, ...);
|
||||
void prtf(const char *fmt, ...);
|
||||
void prt(const char *s);
|
Loading…
Reference in New Issue
Block a user