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_ */