vtgl

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

util.h (8112B)


      1 /* See LICENSE for copyright details */
      2 #ifndef _UTIL_H_
      3 #define _UTIL_H_
      4 
      5 #include <stdint.h>
      6 #include <stddef.h>
      7 
      8 #ifndef asm
      9 #define asm __asm__
     10 #endif
     11 
     12 #ifdef _DEBUG
     13 #define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while(0)
     14 #define DEBUG_EXPORT
     15 #else
     16 #define ASSERT(c) do { (void)(c); } while(0)
     17 #define DEBUG_EXPORT static
     18 #endif
     19 
     20 #ifndef static_assert
     21 #define static_assert _Static_assert
     22 #endif
     23 
     24 #define MEGABYTE (1024ULL * 1024ULL)
     25 
     26 #define ARRAY_COUNT(a)   (sizeof(a) / sizeof(*a))
     27 #define ABS(a)           ((a) < 0 ? (-a) : (a))
     28 #define BETWEEN(x, a, b) ((x) >= (a) && (x) <= (b))
     29 #define CLAMP(x, a, b)   ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x))
     30 #define MAX(a, b)        ((a) >= (b) ? (a) : (b))
     31 #define MIN(a, b)        ((a) <= (b) ? (a) : (b))
     32 #define SGN(a)           ((a) < 0 ? (-1) : (1))
     33 
     34 #define ISCONTROLC0(c)   (BETWEEN((c), 0, 0x1F) || (c) == 0x7F)
     35 #define ISCONTROL(c)     (ISCONTROLC0(c))
     36 #define ISSPACE(c)       ((c) == ' ' || (c) == '\n' || (c) == '\t')
     37 #define ISPRINT(c)       BETWEEN((c), ' ', '~')
     38 
     39 #define ISPOWEROFTWO(a) (((a) & ((a) - 1)) == 0)
     40 
     41 /* NOTE: GLFW does not sequentially number keys so switch statement will never be optimized */
     42 #define ENCODE_KEY(action, mod, key) (((action) << 24) | ((mod) << 16) | ((key) & 0xFFFF))
     43 
     44 #define BACKLOG_SIZE  (16 * MEGABYTE)
     45 #define BACKLOG_LINES (8192UL)
     46 
     47 #define ALT_BACKLOG_SIZE  (2 * MEGABYTE)
     48 #define ALT_BACKLOG_LINES (1024UL)
     49 
     50 typedef float     f32;
     51 typedef double    f64;
     52 typedef int8_t    i8;
     53 typedef uint8_t   u8;
     54 typedef uint16_t  u16;
     55 typedef int16_t   i16;
     56 typedef int32_t   i32;
     57 typedef uint32_t  u32;
     58 typedef uint32_t  b32;
     59 typedef uint64_t  u64;
     60 typedef ptrdiff_t size;
     61 
     62 typedef union {
     63 	struct { i32 x, y; };
     64 	struct { i32 w, h; };
     65 	i32 E[2];
     66 } iv2;
     67 
     68 typedef union {
     69 	struct { u32 x, y; };
     70 	struct { u32 w, h; };
     71 	u32 E[2];
     72 } uv2;
     73 
     74 typedef union {
     75 	struct { f32 x, y; };
     76 	struct { f32 w, h; };
     77 	f32 E[2];
     78 } v2;
     79 
     80 typedef union {
     81 	struct { f32 x, y, z, w; };
     82 	struct { f32 r, g, b, a; };
     83 	f32 E[4];
     84 } v4;
     85 
     86 typedef struct { v2 pos, size; } Rect;
     87 
     88 typedef union {
     89 	/* NOTE: this assumes little endian */
     90 	struct { u8 a, b, g, r; };
     91 	u32 rgba;
     92 } Colour;
     93 
     94 typedef struct { u8 *beg, *end; } Arena;
     95 
     96 typedef struct { size len; u8 *data; } s8;
     97 #define s8(s) (s8){.len = ARRAY_COUNT(s) - 1, .data = (u8 *)s}
     98 
     99 typedef struct { iv2 start, end; } Range;
    100 #define INVALID_RANGE_END (iv2){.x = -1, .y = -1}
    101 
    102 enum cell_attribute {
    103 	ATTR_NULL       = 0,
    104 	ATTR_BOLD       = 1 << 0,
    105 	ATTR_ITALIC     = 1 << 1,
    106 	ATTR_FAINT      = 1 << 2,
    107 	ATTR_UNDERLINED = 1 << 3,
    108 	ATTR_BLINK      = 1 << 4,
    109 	ATTR_INVERSE    = 1 << 5,
    110 	ATTR_INVISIBLE  = 1 << 6,
    111 	ATTR_STRUCK     = 1 << 7,
    112 	ATTR_WIDE       = 1 << 8,
    113 	ATTR_WDUMMY     = 1 << 9, /* NOTE: used to skip cells when copying */
    114 };
    115 
    116 typedef struct {
    117 	Colour fg, bg;
    118 	u32 attr;
    119 } CellStyle;
    120 
    121 typedef struct {
    122 	u32 cp;
    123 	CellStyle style;
    124 } Cell;
    125 
    126 enum cursor_state {
    127 	CURSOR_NORMAL    = 0 << 0,
    128 	CURSOR_WRAP_NEXT = 1 << 0,
    129 	CURSOR_ORIGIN    = 1 << 1,
    130 };
    131 
    132 typedef struct {
    133 	iv2               pos;
    134 	CellStyle         style;
    135 	enum cursor_state state;
    136 } Cursor;
    137 
    138 typedef Cell *Row;
    139 
    140 typedef struct {
    141 	Cell *cells;
    142 	size cells_count;
    143 	size cells_alloc_size;
    144 
    145 	Row  *rows;
    146 	size rows_count;
    147 	size rows_alloc_size;
    148 } Framebuffer;
    149 
    150 /* NOTE: virtual memory ring buffer */
    151 typedef struct {
    152 	size  cap;
    153 	size  filled;
    154 	size  widx;
    155 	u8   *buf;
    156 } RingBuf;
    157 
    158 typedef struct {
    159 	u8 *start, *end;
    160 	b32 has_unicode;
    161 	CellStyle cursor_state;
    162 } Line;
    163 
    164 typedef struct {
    165 	size cap;
    166 	size filled;
    167 	size widx;
    168 	Line *buf;
    169 } LineBuf;
    170 
    171 typedef struct {
    172 	RingBuf     log;
    173 	LineBuf     lines;
    174 	Framebuffer fb;
    175 	/* NOTE: the position of the cursor the last time a new line was blitted
    176 	 * and the index of the line. This is needed because we blit whole lines
    177 	 * at a time unlike traditional terminal emulators which just operate as
    178 	 * a state machine. Any time a line hasn't played to completion we must
    179 	 * restart it from the original location lest it unintentionally cause a
    180 	 * screen scroll. */
    181 	iv2         last_cursor_pos;
    182 	size        last_line_idx;
    183 } TermView;
    184 
    185 #define GL_RENDER_UNIFORMS \
    186 	X(Pmat)            \
    187 	X(charmap)         \
    188 	X(texcolour)       \
    189 	X(texscale)        \
    190 	X(texslot)         \
    191 	X(vertoff)         \
    192 	X(vertscale)
    193 
    194 #define GL_POST_UNIFORMS \
    195 	X(Pmat)          \
    196 	X(param)         \
    197 	X(texslot)       \
    198 	X(vertscale)
    199 
    200 enum gl_flags {
    201 	NEEDS_RESIZE           = 1 << 0,
    202 	NEEDS_BLIT             = 1 << 1,
    203 	NEEDS_REFILL           = 1 << 2,
    204 	NEEDS_FULL_REFILL      = 1 << 3,
    205 
    206 	UPDATE_RENDER_UNIFORMS = 1 << 29,
    207 	UPDATE_POST_UNIFORMS   = 1 << 30,
    208 };
    209 
    210 enum win_mode {
    211 	WIN_MODE_APPCURSOR  = 1 << 0,
    212 	WIN_MODE_HIDECURSOR = 1 << 1,
    213 	WIN_MODE_BRACKPASTE = 1 << 2,
    214 	WIN_MODE_8BIT       = 1 << 3,
    215 	WIN_MODE_REVERSE    = 1 << 4,
    216 };
    217 
    218 enum shader_stages {
    219 	SHADER_RENDER,
    220 	SHADER_POST,
    221 	SHADER_LAST
    222 };
    223 
    224 typedef struct {
    225 	GLFWwindow *window;
    226 	v2          window_size;
    227 
    228 	f32 dt;
    229 
    230 	u32 vao, vbo;
    231 
    232 	u32 fb, fb_tex, fb_tex_unit;
    233 
    234 	u32 programs[SHADER_LAST];
    235 	#define X(name) i32 name;
    236 	union {
    237 		struct { GL_RENDER_UNIFORMS };
    238 		i32 uniforms[7];
    239 	} render;
    240 	union {
    241 		struct { GL_POST_UNIFORMS };
    242 		i32 uniforms[4];
    243 	} post;
    244 	#undef X
    245 
    246 	u32 flags;
    247 	u32 mode;
    248 
    249 	u32    glyph_tex;
    250 } GLCtx;
    251 
    252 /* NOTE: This must match the number in the shaders & the number glyphs in
    253  * the gpu glyph cache. By doing this we ensure that filling a single push buffer
    254  * will not evict a needed glyph texture from the GPU */
    255 #define PUSH_BUFFER_CAP 512
    256 typedef struct {
    257 	v2  vertscales[PUSH_BUFFER_CAP];
    258 	v2  vertoffsets[PUSH_BUFFER_CAP];
    259 	v2  texscales[PUSH_BUFFER_CAP];
    260 	uv2 texcolours[PUSH_BUFFER_CAP];
    261 	i32 charmap[PUSH_BUFFER_CAP];
    262 	u32 count;
    263 } RenderPushBuffer;
    264 
    265 #define MAX_FONT_SIZE       128
    266 
    267 enum conversion_status { CR_FAILURE, CR_SUCCESS };
    268 struct conversion_result {
    269 	i32   status;
    270 	char *unparsed;
    271 	union { i32 i; f32 f; Colour colour;};
    272 };
    273 
    274 #include "util.c"
    275 
    276 #define STB_TRUETYPE_IMPLEMENTATION
    277 #define STB_STATIC
    278 #include "extern/stb_truetype.h"
    279 
    280 #ifdef __unix__
    281 #include "os_unix.c"
    282 #else
    283 #error Unsupported Platform!
    284 #endif
    285 
    286 enum face_style {
    287 	FS_NORMAL,
    288 	FS_BOLD,
    289 	FS_ITALIC,
    290 	FS_BOLD_ITALIC,
    291 	FS_LAST
    292 };
    293 
    294 typedef struct {
    295 	char *path;
    296 	i32   height;
    297 } FontDesc;
    298 
    299 typedef struct {
    300 	stbtt_fontinfo  font_info;
    301 	u8             *buf;
    302 	i32             bufsize;
    303 	i32             fontsize;
    304 	f32             stbtt_scale;
    305 } Font;
    306 
    307 typedef Font FontFamily[FS_LAST];
    308 
    309 #define GLYPH_CACHE_LEN PUSH_BUFFER_CAP
    310 typedef struct {
    311 	/* distance to shift glyph from bounding box origin */
    312 	iv2 delta;
    313 	/* rendered glyph bitmap data (pixels) */
    314 	uv2 size;
    315 } Glyph;
    316 
    317 typedef struct {
    318 	Glyph g;
    319 	u32   cp;
    320 	u32   next_with_same_hash;
    321 	u16   prev, next;
    322 	b32   uploaded_to_gpu;
    323 } CachedGlyph;
    324 
    325 typedef struct {
    326 	u32 hit_count;
    327 	u32 miss_count;
    328 	u32 recycle_count;
    329 } GlyphCacheStats;
    330 
    331 typedef struct {
    332 	CachedGlyph     *glyphs;
    333 	u32             *hash_table;
    334 	u32              cache_len;
    335 	GlyphCacheStats  stats;
    336 } GlyphCache;
    337 
    338 typedef struct {
    339 	FontFamily  *fonts;
    340 	u32          nfonts;
    341 	uv2          size;
    342 	i32          baseline;
    343 	GlyphCache   glyph_cache;
    344 } FontAtlas;
    345 
    346 typedef union {
    347 	i32   i;
    348 	f32   f;
    349 	void *v;
    350 } Arg;
    351 
    352 #define DOUBLE_CLICK_TIME 0.5f
    353 enum selection_states {
    354 	SS_NONE,
    355 	SS_CHAR,
    356 	SS_WORDS,
    357 };
    358 
    359 typedef struct {
    360 	Range range;
    361 	Range anchor;
    362 	v2    mouse_start;
    363 	f32   click_param;
    364 	enum  selection_states state;
    365 } Selection;
    366 
    367 #define ESC_ARG_SIZ 6
    368 typedef struct {
    369 	s8 raw;
    370 	i32 argv[ESC_ARG_SIZ];
    371 	i32 argc;
    372 	u8 mode;
    373 	u8 priv;
    374 } CSI;
    375 
    376 typedef struct {
    377 	s8  raw;
    378 	s8  arg;
    379 	i32 cmd;
    380 } OSC;
    381 
    382 enum escape_mode {
    383 	EM_CSI = 1 << 0,
    384 	EM_STR = 1 << 1,
    385 };
    386 
    387 enum terminal_mode {
    388 	TM_ALTSCREEN = 1 << 0,
    389 	TM_REPLACE   = 1 << 1,
    390 	TM_AUTO_WRAP = 1 << 2,
    391 	TM_CRLF      = 1 << 3,
    392 };
    393 
    394 typedef struct {
    395 	GLCtx     gl;
    396 	FontAtlas fa;
    397 
    398 	Arena arena_for_frame;
    399 
    400 	Selection selection;
    401 	Cursor    cursor;
    402 	Cursor    saved_cursors[2];
    403 	TermView  views[2];
    404 	i32       view_idx;
    405 	i32       scroll_offset;
    406 
    407 	size unprocessed_bytes;
    408 
    409 	os_child child;
    410 
    411 	uv2 size;
    412 	/* NOTE: scrolling region */
    413 	u32 top, bot;
    414 
    415 	CSI  csi;
    416 
    417 	enum escape_mode   escape;
    418 	enum terminal_mode mode;
    419 
    420 	char saved_title[1024];
    421 } Term;
    422 
    423 #endif /* _UTIL_H_ */