vtgl

terminal emulator implemented in OpenGL
git clone anongit@rnpnr.xyz:vtgl.git
Log | Files | Refs | Feed | LICENSE

util.h (9794B)


      1 /* See LICENSE for copyright details */
      2 #ifndef _UTIL_H_
      3 #define _UTIL_H_
      4 
      5 typedef union {
      6 	struct { u32 x, y; };
      7 	struct { u32 w, h; };
      8 	u32 E[2];
      9 } uv2;
     10 
     11 typedef __attribute__((aligned(16))) union {
     12 	struct { f32 x, y, z, w; };
     13 	struct { f32 r, g, b, a; };
     14 	f32 E[4];
     15 } v4;
     16 
     17 typedef struct { v2 pos, size; } Rect;
     18 
     19 typedef union {
     20 	/* NOTE: this assumes little endian */
     21 	struct { u8 a, b, g, r; };
     22 	u32 rgba;
     23 } Colour;
     24 
     25 enum variable_type {
     26 	VT_NULL,
     27 
     28 	VT_B32,
     29 	VT_U32,
     30 	VT_I32,
     31 	VT_F32,
     32 	VT_V4,
     33 	VT_S8,
     34 	VT_RANGE,
     35 	VT_SLL_VECTOR,
     36 
     37 	VT_GROUP,
     38 };
     39 
     40 struct Variable;
     41 
     42 typedef struct VariableLink {
     43 	struct VariableLink *prev;
     44 	struct VariableLink *next;
     45 	struct Variable     *var;
     46 } VariableLink;
     47 
     48 typedef struct {
     49 	VariableLink *next;
     50 	u32           count;
     51 } SLLVariableVector;
     52 
     53 #define SLLPush(sll, new) do {     \
     54 	(new)->next = (sll)->next; \
     55 	(sll)->next = (new);       \
     56 } while(0)
     57 
     58 #define SLLVariableVectorPush(a, sll, var) do {          \
     59 	VariableLink *vl = push_struct(a, VariableLink); \
     60 	SLLPush(sll, vl);                                \
     61 	(sll)->count++;                                  \
     62 	vl->var  = var;                                  \
     63 } while(0)
     64 
     65 #define DLLPushDown(head, new) do {  \
     66 	(new)->last  = (head);       \
     67 	(new)->next  = (head)->next; \
     68 	(head)->next = (new);        \
     69 } while(0)
     70 
     71 typedef struct Variable {
     72 	union {
     73 		b32 b32;
     74 		u32 u32;
     75 		i32 i32;
     76 		f32 f32;
     77 		s8  s8;
     78 		v4  v4;
     79 
     80 		Range range;
     81 
     82 		VariableLink      group;
     83 		SLLVariableVector vector;
     84 	};
     85 	enum variable_type type;
     86 } Variable;
     87 
     88 enum cell_attribute {
     89 	ATTR_NULL       = 0,
     90 	ATTR_BOLD       = 1 << 0,
     91 	ATTR_ITALIC     = 1 << 1,
     92 	ATTR_WIDE       = 1 << 2,
     93 	ATTR_WDUMMY     = 1 << 3, /* NOTE: used to skip cells when copying */
     94 	ATTR_FAINT      = 1 << 4,
     95 	ATTR_UNDERLINED = 1 << 5,
     96 	ATTR_BLINK      = 1 << 6,
     97 	ATTR_INVERSE    = 1 << 7,
     98 	ATTR_INVISIBLE  = 1 << 8,
     99 	ATTR_STRUCK     = 1 << 9,
    100 };
    101 #define ATTR_SHADER_MASK (ATTR_FAINT|ATTR_UNDERLINED|ATTR_BLINK|ATTR_INVERSE|ATTR_INVISIBLE|ATTR_STRUCK)
    102 #define ATTR_STYLE_MASK  (ATTR_BOLD|ATTR_ITALIC|ATTR_WIDE|ATTR_WDUMMY)
    103 
    104 #define SHADER_PACK_ATTR(a)  (((a) & ATTR_SHADER_MASK) >> 4)
    105 #define SHADER_PACK_FG(c, a) (((c) & 0xFFFFFF00) | SHADER_PACK_ATTR(a))
    106 #define SHADER_PACK_BG(c, a) (((c) & 0xFFFFFF00) | ((a) & ATTR_STYLE_MASK))
    107 
    108 typedef struct {
    109 	u32 cp;
    110 	u32 fg;
    111 	u32 bg;
    112 } Cell;
    113 
    114 enum cursor_state {
    115 	CURSOR_NORMAL    = 0 << 0,
    116 	CURSOR_WRAP_NEXT = 1 << 0,
    117 	CURSOR_ORIGIN    = 1 << 1,
    118 };
    119 
    120 typedef struct {
    121 	Colour fg, bg;
    122 	u32 attr;
    123 } CellStyle;
    124 
    125 typedef __attribute__((aligned(32))) struct {
    126 	CellStyle         style;
    127 	enum cursor_state state;
    128 	iv2               pos;
    129 
    130 	/* NOTE: 4 available charset slots and the selected charset slot to look in.
    131 	 * xterm stores this as part of the cursor so we do here as well. */
    132 	u32 charset_index;
    133 	u8  charsets[4];
    134 } Cursor;
    135 
    136 typedef Cell *Row;
    137 
    138 typedef struct {
    139 	Cell *cells;
    140 	Row  *rows;
    141 	OSMemoryBlock backing_store;
    142 } Framebuffer;
    143 
    144 typedef struct {
    145 	u8 *start, *end;
    146 	b32 has_unicode;
    147 	CellStyle cursor_state;
    148 } Line;
    149 
    150 typedef struct {
    151 	iz    capacity;
    152 	iz    filled;
    153 	iz    count;
    154 	Line *data;
    155 } LineBuffer;
    156 
    157 typedef struct {
    158 	OSRingBuffer log;
    159 	LineBuffer   lines;
    160 	Framebuffer  fb;
    161 } TermView;
    162 
    163 enum terminal_mode {
    164 	TM_ALTSCREEN = 1 << 0,
    165 	TM_REPLACE   = 1 << 1,
    166 	TM_AUTO_WRAP = 1 << 2,
    167 	TM_CRLF      = 1 << 3,
    168 	TM_UTF8      = 1 << 4,
    169 
    170 	TM_ALL_MASK = TM_UTF8|(TM_UTF8 - 1),
    171 };
    172 
    173 enum window_mode {
    174 	WM_APPCURSOR  = 1 << 0,
    175 	WM_HIDECURSOR = 1 << 1,
    176 	WM_BRACKPASTE = 1 << 2,
    177 	WM_8BIT       = 1 << 3,
    178 	WM_REVERSE    = 1 << 4,
    179 	WM_MOUSE_X10  = 1 << 5,
    180 	WM_MOUSE_BTN  = 1 << 6,
    181 	WM_MOUSE_TRK  = 1 << 7,
    182 	WM_MOUSE_SGR  = 1 << 8,
    183 
    184 	WM_MOUSE_MASK = WM_MOUSE_X10|WM_MOUSE_BTN|WM_MOUSE_TRK|WM_MOUSE_SGR,
    185 
    186 	WM_ALL_MASK = WM_MOUSE_SGR|(WM_MOUSE_SGR - 1),
    187 };
    188 
    189 #define MODE_STATE_ALL_MASK (ModeState){.term = TM_ALL_MASK, .win = WM_ALL_MASK}
    190 typedef struct {
    191 	enum terminal_mode term;
    192 	enum window_mode   win;
    193 } ModeState;
    194 
    195 #define SHADER_PMAT_LOC 0
    196 
    197 #define GL_POST_UNIFORMS \
    198 	X(param)         \
    199 	X(texslot)
    200 
    201 enum gl_flags {
    202 	RESIZE_RENDERER      = 1 << 0,
    203 
    204 	DRAW_DEBUG_OVERLAY   = 1 << 30,
    205 };
    206 
    207 /* X(enumerant, file_name) */
    208 #define FRAGMENT_SHADERS \
    209 	X(RENDER, "frag_render")    \
    210 	X(RECTS,  "frag_for_rects") \
    211 	X(POST,   "frag_post")
    212 
    213 typedef enum {
    214 	#define X(en, fn) SID_ ##en,
    215 	FRAGMENT_SHADERS
    216 	#undef X
    217 	SID_LAST
    218 } ShaderID;
    219 
    220 typedef struct {
    221 	iv2 cell_size;
    222 	iv2 term_size_in_cells;
    223 	iv2 term_size_in_pixels;
    224 
    225 	iv2 top_left_margin;
    226 	u32 margin_colour;
    227 
    228 	f32 blink_parameter;
    229 
    230 	f32 strike_min;
    231 	f32 strike_max;
    232 
    233 	f32 underline_min;
    234 	f32 underline_max;
    235 
    236 	u32 reverse_video_mask;
    237 
    238 	u32 _pad[1];
    239 } ShaderParameters;
    240 
    241 static_assert((sizeof(ShaderParameters) & 15) == 0,
    242               "sizeof(ShaderParameters) must be a multiple of 16");
    243 
    244 typedef struct {
    245 	iv2 window_size;
    246 
    247 	u32 vao, vbos[5];
    248 
    249 	u32 fb, fb_tex, fb_tex_unit;
    250 
    251 	ShaderID programs[SID_LAST];
    252 	#define X(name) i32 name;
    253 	struct { GL_POST_UNIFORMS } post;
    254 	#undef X
    255 
    256 	_Alignas(16) ShaderParameters shader_parameters;
    257 	u32 render_shader_ubo;
    258 	u32 render_shader_ssbo;
    259 
    260 	iv2 glyph_bitmap_dim;
    261 	u32 glyph_bitmap_tex;
    262 
    263 	u32 flags;
    264 
    265 	u32 queued_render;
    266 } GLCtx;
    267 
    268 typedef struct {
    269 	u32 gpu_glyph;
    270 	u32 fg;
    271 	u32 bg;
    272 } RenderCell;
    273 
    274 /* TODO: try different sizes; largely depends on how many things we want to batch together */
    275 #define RENDER_PUSH_BUFFER_CAP 8192
    276 typedef __attribute__((aligned(64))) struct {
    277 	v2  positions[RENDER_PUSH_BUFFER_CAP];
    278 	v2  texture_coordinates[RENDER_PUSH_BUFFER_CAP];
    279 	v4  colours[RENDER_PUSH_BUFFER_CAP];
    280 	u32 count;
    281 } RenderPushBuffer;
    282 
    283 #define MIN_FONT_SIZE 8
    284 #define MAX_FONT_SIZE 128
    285 
    286 typedef enum { CR_FAILURE, CR_SUCCESS, CR_OUT_OF_RANGE } conversion_status;
    287 struct conversion_result {
    288 	conversion_status status;
    289 	s8 unparsed;
    290 	union { i32 i; f32 f; Colour colour;};
    291 };
    292 
    293 enum selection_states {
    294 	SS_NONE,
    295 	SS_CHAR,
    296 	SS_WORDS,
    297 };
    298 
    299 typedef struct {
    300 	Range range;
    301 	Range anchor;
    302 	enum  selection_states state;
    303 } Selection;
    304 
    305 typedef struct {
    306 	Row   *rows;
    307 	iv2    cursor;
    308 	iv2    next;
    309 	iv2    end;
    310 	i32    term_width;
    311 } SelectionIterator;
    312 
    313 enum face_style {
    314 	FS_NORMAL      = ATTR_NULL,
    315 	FS_BOLD        = ATTR_BOLD,
    316 	FS_ITALIC      = ATTR_ITALIC,
    317 	FS_BOLD_ITALIC = ATTR_BOLD|ATTR_ITALIC,
    318 	FS_COUNT,
    319 	FS_MASK        = FS_BOLD_ITALIC,
    320 };
    321 
    322 typedef struct {
    323 	i32 h, w;
    324 	i32 baseline;
    325 } FontInfo;
    326 
    327 typedef struct stbtt_fontinfo stbtt_fontinfo;
    328 typedef struct {
    329 	stbtt_fontinfo *font_info;
    330 	u8             *buf;
    331 	i32             bufsize;
    332 	f32             stbtt_scale;
    333 } Font;
    334 
    335 typedef Font FontFamily[FS_COUNT];
    336 
    337 typedef struct {
    338 	u32 cp;
    339 	u32 next_with_same_hash;
    340 	u32 prev;
    341 	u32 next;
    342 	u32 gpu_tile_index;
    343 	u8  tile_count;
    344 	u8  uploaded_to_gpu;
    345 	u16 advance;
    346 	i16 height;
    347 	i16 width;
    348 	i16 x0;
    349 	i16 y0;
    350 } CachedGlyph;
    351 
    352 typedef union {
    353 	struct {
    354 		u32 hit_count;
    355 		u32 miss_count;
    356 		u32 recycle_count;
    357 	};
    358 	u32 E[3];
    359 } GlyphCacheStats;
    360 
    361 typedef struct {
    362 	CachedGlyph     *glyphs;
    363 	u32             *hash_table;
    364 	u8              *occupied_tiles;
    365 	u32              cache_len;
    366 	GlyphCacheStats  stats;
    367 	i32              tiles_in_x;
    368 	i32              tiles_in_y;
    369 } GlyphCache;
    370 
    371 typedef struct {
    372 	FontFamily  *fonts;
    373 	u32          nfonts;
    374 	FontInfo     info;
    375 	GlyphCache   glyph_cache;
    376 } FontAtlas;
    377 
    378 typedef union {
    379 	i32   i;
    380 	f32   f;
    381 	void *v;
    382 } Arg;
    383 
    384 #define INTERACTION_MULTI_CLICK_TIME 0.5f
    385 
    386 enum interaction_types {
    387 	IS_NONE,
    388 	IS_NOP,
    389 	IS_SET,
    390 	IS_DRAG,
    391 
    392 	IS_AUTO,
    393 
    394 	IS_DEBUG,
    395 	IS_TERM,
    396 };
    397 
    398 typedef struct {
    399 	Variable var;
    400 	enum interaction_types type;
    401 } Interaction;
    402 
    403 typedef struct {
    404 	Interaction hot;
    405 	Interaction active;
    406 
    407 	u32 click_count;
    408 	f32 multi_click_t;
    409 
    410 	iv2 last_cell_report;
    411 } InteractionState;
    412 
    413 #define ESC_ARG_SIZ 6
    414 typedef struct {
    415 	s8 raw;
    416 	i32 argv[ESC_ARG_SIZ];
    417 	i32 argc;
    418 	u8 mode;
    419 	u8 priv;
    420 } CSI;
    421 
    422 typedef struct {
    423 	s8  raw;
    424 	s8  arg;
    425 	i32 cmd;
    426 } OSC;
    427 
    428 enum escape_mode {
    429 	EM_CSI = 1 << 0,
    430 	EM_STR = 1 << 1,
    431 };
    432 
    433 enum charsets {
    434 	CS_USA,
    435 	CS_GRAPHIC0,
    436 };
    437 
    438 typedef struct ShaderReloadContext ShaderReloadContext;
    439 
    440 typedef struct RenderCtx {
    441 	RenderPushBuffer *rpb;
    442 	GLCtx            *gl;
    443 	FontAtlas        *fa;
    444 	Arena             a;
    445 } RenderCtx;
    446 
    447 typedef enum {
    448 	WQK_RELOAD_SHADER,
    449 	WQK_RELOAD_ALL_SHADERS,
    450 } WorkQueueWorkKind;
    451 
    452 typedef struct {
    453 	union {
    454 		void                *generic;
    455 		ShaderReloadContext *shader_reload_context;
    456 	};
    457 	WorkQueueWorkKind kind;
    458 } WorkQueueWork;
    459 
    460 typedef struct {
    461 	union {
    462 		u64 queue;
    463 		struct {u32 widx, ridx;};
    464 	};
    465 	WorkQueueWork items[1 << 6];
    466 } WorkQueue;
    467 
    468 struct ShaderReloadContext {
    469 	WorkQueue *work_queue;
    470 	s8         path;
    471 	s8         label;
    472 	ShaderID   shader;
    473 };
    474 
    475 typedef struct {
    476 	GLCtx     gl;
    477 	FontAtlas fa;
    478 	WorkQueue work_queue;
    479 
    480 	Arena arena;
    481 
    482 	/* TODO(rnp): cleanup */
    483 	TerminalInput *input;
    484 
    485 	iptr window;
    486 	iv2  monitor_size;
    487 
    488 	/* TODO(rnp): cleanup */
    489 	Stream error_stream;
    490 
    491 	i32 *sync;
    492 
    493 	ShaderReloadContext shader_reload_contexts[SID_LAST];
    494 
    495 	b32 running;
    496 } RenderThreadContext;
    497 
    498 typedef enum {
    499 	TS_NEEDS_RESIZE = 1 << 0,
    500 	TS_NEEDS_REFILL = 1 << 1,
    501 } TerminalState;
    502 
    503 typedef struct {
    504 	Arena     arena_for_frame;
    505 	TempArena temp_arena;
    506 
    507 	InteractionState interaction;
    508 
    509 	Selection selection;
    510 
    511 	TerminalState state;
    512 
    513 	ModeState mode;
    514 	ModeState saved_mode;
    515 
    516 	Cursor    cursor;
    517 	Cursor    saved_cursors[2];
    518 
    519 	TermView  views[2];
    520 	i32       resize_lock;
    521 	i32       view_idx;
    522 	i32       scroll_offset;
    523 
    524 	iz unprocessed_bytes;
    525 
    526 	iptr child;
    527 
    528 	iv2 size;
    529 	/* NOTE: scrolling region */
    530 	i32 top, bot;
    531 
    532 	CSI  csi;
    533 
    534 	enum escape_mode escape;
    535 
    536 	/* NOTE: this means we limit ourselves to 32 * 32 cells (1024). Even on a 4k sceen
    537 	 * this would mean that cells are ~4px wide which is unreadable */
    538 	u32 tabs[32];
    539 
    540 	Stream saved_title;
    541 	Stream error_stream;
    542 
    543 	RenderThreadContext render_thread;
    544 
    545 	OS *os;
    546 } Term;
    547 
    548 #define LABEL_GL_OBJECT(type, id, s) {s8 _s = (s); glObjectLabel(type, id, _s.len, (c8 *)_s.data);}
    549 
    550 global f32 dt_for_frame;
    551 
    552 #endif /* _UTIL_H_ */