vtgl

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

Commit: 477fc2e932cd6ad0f0cc26b8af380ebd1120c52a
Parent: ab202f5425cc5cd5e2d5f9141d304ccc40e92a7e
Author: Randy Palamar
Date:   Fri, 29 Nov 2024 06:13:25 -0700

untangle some of the header mess

Diffstat:
Mdebug.c | 2--
Mdebug.h | 10----------
Mextern/stb_truetype.h | 2+-
Mfont.c | 40+++++++++++++++++++++++-----------------
Mos_unix.c | 17-----------------
Mplatform_linux_common.c | 20+++++++++++++++++---
Mplatform_linux_x11.c | 4+---
Mtests/test.c | 5+----
Mutil.h | 137++-----------------------------------------------------------------------------
Mvtgl.c | 2+-
Mvtgl.h | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 184 insertions(+), 193 deletions(-)

diff --git a/debug.c b/debug.c @@ -1,5 +1,3 @@ -#include "util.h" - static void dump_lines_to_file(Term *t) { diff --git a/debug.h b/debug.h @@ -73,8 +73,6 @@ typedef struct { #define INVALID_CODE_PATH ASSERT(0) #ifndef _DEBUG -#define ASSERT(c) do { (void)(c); } while(0) -#define DEBUG_EXPORT static #define FRAME_MARK(...) @@ -89,9 +87,6 @@ typedef struct { #else -#define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while(0) -#define DEBUG_EXPORT - enum debug_event_types { DE_INVALID, DE_FRAME_MARK, @@ -147,11 +142,6 @@ static DebugTable g_debug_table; RECORD_DEBUG_META_COMMON(__counter_##name, #name) #define END_NAMED_BLOCK(name) RECORD_DEBUG_EVENT(__counter_##name, DE_END) -typedef struct RenderCtx RenderCtx; -typedef struct TerminalMemory TerminalMemory; -typedef struct TerminalInput TerminalInput; -typedef struct Term Term; - static void dump_lines_to_file(Term *t); static void draw_debug_overlay(TerminalMemory *term_memory, TerminalInput *input, RenderCtx *rc); static void debug_frame_end(TerminalMemory *memory); diff --git a/extern/stb_truetype.h b/extern/stb_truetype.h @@ -353,7 +353,7 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(unsigned char *data, int index); // The following structure is defined publicly so you can declare one on // the stack or as a global or etc, but you should treat it as opaque. -typedef struct { +typedef struct stbtt_fontinfo { unsigned char * data; // pointer to .ttf file int fontstart; // offset of start of font diff --git a/font.c b/font.c @@ -21,6 +21,10 @@ static u16 graphic_0[62] = { 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00B7, }; +#define STB_TRUETYPE_IMPLEMENTATION +#define STB_STATIC +#include "extern/stb_truetype.h" + static b32 init_font(Font *f, char *font_path, i32 font_size) { @@ -28,11 +32,11 @@ init_font(Font *f, char *font_path, i32 font_size) os_mapped_file map = os_map_file(font_path, OS_MAP_READ, OS_MAP_PRIVATE); if (map.len) { - result = stbtt_InitFont(&f->font_info, map.data, 0); + result = stbtt_InitFont(f->font_info, map.data, 0); if (result) { f->bufsize = map.len; f->buf = map.data; - f->stbtt_scale = stbtt_ScaleForMappingEmToPixels(&f->font_info, font_size); + f->stbtt_scale = stbtt_ScaleForMappingEmToPixels(f->font_info, font_size); } else { /* TODO: leak */ os_write_err_msg(s8("init_font: failed on: ")); @@ -206,7 +210,7 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, u32 font_id, enum face_style style /* NOTE: first try the requested font id */ if (font_id < fa->nfonts && fa->fonts[font_id][style].buf) { - glyph_idx = stbtt_FindGlyphIndex(&fa->fonts[font_id][style].font_info, cp); + glyph_idx = stbtt_FindGlyphIndex(fa->fonts[font_id][style].font_info, cp); if (glyph_idx) font_idx = font_id; } @@ -216,10 +220,10 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, u32 font_id, enum face_style style u32 test_style = style; if (!fa->fonts[i][test_style].buf) test_style = FS_NORMAL; - glyph_idx = stbtt_FindGlyphIndex(&fa->fonts[i][test_style].font_info, cp); + glyph_idx = stbtt_FindGlyphIndex(fa->fonts[i][test_style].font_info, cp); if (!glyph_idx) { test_style = FS_NORMAL; - glyph_idx = stbtt_FindGlyphIndex(&fa->fonts[i][test_style].font_info, cp); + glyph_idx = stbtt_FindGlyphIndex(fa->fonts[i][test_style].font_info, cp); } if (glyph_idx) { font_idx = i; @@ -232,7 +236,7 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, u32 font_id, enum face_style style Font *f = &fa->fonts[font_idx][style]; f32 scale = f->stbtt_scale; i32 x0, y0, x1, y1, advance, left_bearing; - stbtt_GetGlyphBitmapBoxSubpixel(&f->font_info, glyph_idx, scale, scale, 0, 0, + stbtt_GetGlyphBitmapBoxSubpixel(f->font_info, glyph_idx, scale, scale, 0, 0, &x0, &y0, &x1, &y1); /* NOTE: this looks weird but some 'wide' glyphs are not actually wide but still @@ -245,7 +249,7 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, u32 font_id, enum face_style style i32 height = y1 - y0; i32 width = x1 - x0; - stbtt_GetGlyphHMetrics(&f->font_info, glyph_idx, &advance, &left_bearing); + stbtt_GetGlyphHMetrics(f->font_info, glyph_idx, &advance, &left_bearing); cg->advance = scale * advance; cg->height = MIN(height, fa->info.h); cg->width = MIN(width, fa->info.w * cg->tile_count); @@ -256,7 +260,7 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, u32 font_id, enum face_style style ASSERT(cg->width <= 2 * fa->info.w); u8 *render_buf = alloc(a, u8, width * height); - stbtt_MakeGlyphBitmapSubpixel(*a, &f->font_info, render_buf, width, height, + stbtt_MakeGlyphBitmapSubpixel(*a, f->font_info, render_buf, width, height, width, scale, scale, 0, 0, glyph_idx); uv2 tile_coord = unpack_gpu_tile_coord(cg->gpu_tile_index); @@ -339,16 +343,16 @@ compute_font_info(Font *font, u32 font_size) static s8 ascii = s8(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"\ "`abcdefghijklmnopqrstuvwxyz{|}~"); - f32 scale = stbtt_ScaleForMappingEmToPixels(&font->font_info, font_size); + f32 scale = stbtt_ScaleForMappingEmToPixels(font->font_info, font_size); i32 min_y = 0; i32 max_height = 0; f32 width = 0; for (size i = 0; i < ascii.len; i++) { - u32 glyph_idx = stbtt_FindGlyphIndex(&font->font_info, ascii.data[i]); + u32 glyph_idx = stbtt_FindGlyphIndex(font->font_info, ascii.data[i]); i32 x0, y0, x1, y1, advance, left_bearing; - stbtt_GetGlyphBitmapBoxSubpixel(&font->font_info, glyph_idx, scale, scale, 0, 0, + stbtt_GetGlyphBitmapBoxSubpixel(font->font_info, glyph_idx, scale, scale, 0, 0, &x0, &y0, &x1, &y1); - stbtt_GetGlyphHMetrics(&font->font_info, glyph_idx, &advance, &left_bearing); + stbtt_GetGlyphHMetrics(font->font_info, glyph_idx, &advance, &left_bearing); width += scale * advance; max_height = MAX(max_height, y1 - y0); @@ -361,11 +365,11 @@ compute_font_info(Font *font, u32 font_size) continue; graphic_0_count++; - u32 glyph_idx = stbtt_FindGlyphIndex(&font->font_info, graphic_0[i]); + u32 glyph_idx = stbtt_FindGlyphIndex(font->font_info, graphic_0[i]); i32 x0, y0, x1, y1, advance, left_bearing; - stbtt_GetGlyphBitmapBoxSubpixel(&font->font_info, glyph_idx, scale, scale, 0, 0, + stbtt_GetGlyphBitmapBoxSubpixel(font->font_info, glyph_idx, scale, scale, 0, 0, &x0, &y0, &x1, &y1); - stbtt_GetGlyphHMetrics(&font->font_info, glyph_idx, &advance, &left_bearing); + stbtt_GetGlyphHMetrics(font->font_info, glyph_idx, &advance, &left_bearing); width += scale * advance; max_height = MAX(max_height, y1 - y0); @@ -419,7 +423,7 @@ shift_font_sizes(FontAtlas *fa, i32 size_delta) for (u32 j = 0; j < FS_COUNT; j++) { Font *f = &fa->fonts[i][j]; if (!f->buf) continue; - f->stbtt_scale = stbtt_ScaleForMappingEmToPixels(&f->font_info, font_size); + f->stbtt_scale = stbtt_ScaleForMappingEmToPixels(f->font_info, font_size); } } } @@ -438,7 +442,9 @@ init_fonts(FontAtlas *fa, Arena *a, iv2 glyph_bitmap_dim) for (u32 i = 0; i < FS_COUNT; i++) { if (!g_fonts[j][i]) continue; - if (init_font(&fa->fonts[fa->nfonts][i], g_fonts[j][i], font_size)) { + Font *f = fa->fonts[fa->nfonts] + i; + f->font_info = alloc(a, typeof(*f->font_info), 1); + if (init_font(f, g_fonts[j][i], font_size)) { result = 1; } else { os_write_err_msg(s8("failed to load font: ")); diff --git a/os_unix.c b/os_unix.c @@ -9,8 +9,6 @@ #include <time.h> #include <unistd.h> -typedef s8 os_mapped_file; - typedef struct { iptr handle; iptr process_id; @@ -28,21 +26,6 @@ os_get_time(void) return result; } -static void -os_write_err_msg(s8 msg) -{ - write(STDERR_FILENO, msg.data, msg.len); -} - -__attribute__((noreturn)) -static void -os_fatal(s8 msg) -{ - os_write_err_msg(msg); - _exit(1); - __builtin_unreachable(); -} - static PLATFORM_GET_FILESTATS_FN(posix_get_file_stats) { struct stat sb = {0}; diff --git a/platform_linux_common.c b/platform_linux_common.c @@ -9,9 +9,6 @@ #define MAP_FIXED 0x10 #define MAP_ANON 0x20 -#include "util.h" -#include "vtgl.h" - #ifndef VERSION #define VERSION "unknown" #endif @@ -37,6 +34,22 @@ typedef struct { #define LINUX_INOTIFY_MASK (IN_CLOSE|IN_MODIFY) +static void +os_write_err_msg(s8 msg) +{ + syscall3(SYS_write, 2, (iptr)msg.data, msg.len); +} + +__attribute__((noreturn)) +static void +os_fatal(s8 msg) +{ + os_write_err_msg(msg); + syscall1(SYS_exit, 1); + __builtin_unreachable(); +} + + static MemoryBlock linux_block_alloc(size requested_size) { @@ -84,3 +97,4 @@ usage(char *argv0, Stream *err) os_fatal(stream_to_s8(err)); } +#include "os_unix.c" diff --git a/platform_linux_x11.c b/platform_linux_x11.c @@ -12,8 +12,7 @@ typedef void *Window; #define GLFW_NATIVE_INCLUDE_NONE #include <GLFW/glfw3native.h> -/* TODO: main should be defined in this file instead */ -#include "platform_linux_amd64.c" +#include "vtgl.h" i32 XConnectionNumber(void *display); i32 XPending(void *display); @@ -412,7 +411,6 @@ static PLATFORM_ADD_FILE_WATCH_FN(linux_add_file_watch) linux_ctx.file_watches[idx].user_ctx = user_ctx; } -#include <stdio.h> static void linux_render_thread_entry(struct stack_base *stack) { diff --git a/tests/test.c b/tests/test.c @@ -1,10 +1,7 @@ /* See LICENSE for copyright details */ -#include "util.h" +#include "vtgl.h" #include "config.h" -/* TODO: properly use platform layer according to os */ -#include "../platform_linux_amd64.c" - /* NOTE: stubs for stuff we aren't testing */ static void get_gpu_glyph_index(Arena, void *, void *, u32, u32, u32, CachedGlyph **); diff --git a/util.h b/util.h @@ -2,91 +2,12 @@ #ifndef _UTIL_H_ #define _UTIL_H_ -#include <stdint.h> -#include <stddef.h> - -#include <immintrin.h> - -#ifndef asm -#define asm __asm__ -#endif - -#ifndef typeof -#define typeof __typeof__ -#endif - -#ifndef static_assert -#define static_assert _Static_assert -#endif - -#define PI 3.1415926535897932384f -#define KILOBYTE (1024ULL) -#define MEGABYTE (1024ULL * 1024ULL) -#define MB(a) ((a) << 20ULL) - -#define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a)) -#define ABS(a) ((a) < 0 ? (-a) : (a)) -#define BETWEEN(x, a, b) ((x) >= (a) && (x) <= (b)) -#define CLAMP(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)) -#define MAX(a, b) ((a) >= (b) ? (a) : (b)) -#define MIN(a, b) ((a) <= (b) ? (a) : (b)) -#define SGN(a) ((a) < 0 ? (-1) : (1)) - -#define SAFE_RATIO_1(a, b) ((b) ? (a) / (b) : (a)) - -#define ISCONTROLC0(c) (BETWEEN((c), 0, 0x1F) || (c) == 0x7F) -#define ISCONTROLC1(c) (BETWEEN((c), 0x80, 0x9F)) -#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) -#define ISSPACE(c) ((c) == ' ' || (c) == '\n' || (c) == '\t') -#define ISPRINT(c) BETWEEN((c), ' ', '~') - -#define ISPOWEROFTWO(a) (((a) & ((a) - 1)) == 0) - -/* NOTE: GLFW does not sequentially number keys so switch statement will never be optimized */ -#define ENCODE_KEY(action, mod, key) (((action) << 24) | ((mod) << 16) | ((key) & 0xFFFF)) - -#define BACKLOG_SIZE (16 * MEGABYTE) -#define BACKLOG_LINES (8192UL) - -#define ALT_BACKLOG_SIZE (2 * MEGABYTE) -#define ALT_BACKLOG_LINES (1024UL) - -#define I64_MIN INT64_MIN - -typedef float f32; -typedef double f64; -typedef char c8; -typedef int8_t i8; -typedef uint8_t u8; -typedef int16_t i16; -typedef uint16_t u16; -typedef int32_t i32; -typedef uint32_t u32; -typedef uint32_t b32; -typedef int64_t i64; -typedef uint64_t u64; -typedef ptrdiff_t iptr; -typedef ptrdiff_t size; -typedef size_t usize; - -typedef union { - struct { i32 x, y; }; - struct { i32 w, h; }; - i32 E[2]; -} iv2; - typedef union { struct { u32 x, y; }; struct { u32 w, h; }; u32 E[2]; } uv2; -typedef union { - struct { f32 x, y; }; - struct { f32 w, h; }; - f32 E[2]; -} v2; - typedef __attribute__((aligned(16))) union { struct { f32 x, y, z, w; }; struct { f32 r, g, b, a; }; @@ -101,17 +22,6 @@ typedef union { u32 rgba; } Colour; -typedef struct { u8 *beg, *end; } Arena; -typedef struct { Arena *arena; u8 *old_beg; } TempArena; - -typedef struct { void *memory; size size; } MemoryBlock; - -typedef struct { size len; u8 *data; } s8; -#define s8(s) (s8){.len = ARRAY_COUNT(s) - 1, .data = (u8 *)s} - -typedef struct { iv2 start, end; } Range; -#define INVALID_RANGE_END (iv2){.x = -1, .y = -1} - enum variable_type { VT_NULL, @@ -132,27 +42,6 @@ typedef struct { void *value; } Variable; -typedef struct { - u8 *buf; - u32 cap; - u32 widx; - b32 errors; -} Stream; - -typedef struct { - size size; - u64 timestamp; -} FileStats; - -#define INVALID_FILE (-1) -enum file_attribute { - FA_READ = 1 << 0, - FA_WRITE = 1 << 1, - FA_APPEND = 1 << 2, -}; - -#include "debug.h" - enum cell_attribute { ATTR_NULL = 0, ATTR_BOLD = 1 << 0, @@ -209,14 +98,6 @@ typedef struct { MemoryBlock backing_store; } Framebuffer; -/* NOTE: virtual memory ring buffer */ -typedef struct { - size cap; - size filled; - size widx; - u8 *buf; -} RingBuf; - typedef struct { u8 *start, *end; b32 has_unicode; @@ -389,21 +270,6 @@ typedef struct { u32 term_width; } SelectionIterator; -#include <immintrin.h> - -#include "vtgl.h" -#include "util.c" - -#define STB_TRUETYPE_IMPLEMENTATION -#define STB_STATIC -#include "extern/stb_truetype.h" - -#ifdef __unix__ -#include "os_unix.c" -#else -#error Unsupported Platform! -#endif - enum face_style { FS_NORMAL = ATTR_NULL, FS_BOLD = ATTR_BOLD, @@ -418,8 +284,9 @@ typedef struct { i32 baseline; } FontInfo; +typedef struct stbtt_fontinfo stbtt_fontinfo; typedef struct { - stbtt_fontinfo font_info; + stbtt_fontinfo *font_info; u8 *buf; i32 bufsize; f32 stbtt_scale; diff --git a/vtgl.c b/vtgl.c @@ -3,7 +3,7 @@ #define GL_GLEXT_PROTOTYPES #include <GL/glcorearb.h> -#include "util.h" +#include "vtgl.h" #include "config.h" diff --git a/vtgl.h b/vtgl.h @@ -2,6 +2,133 @@ #ifndef _VTGL_H_ #define _VTGL_H_ +#include <stddef.h> +#include <stdint.h> + +#include <immintrin.h> + +#ifndef asm +#define asm __asm__ +#endif + +#ifndef typeof +#define typeof __typeof__ +#endif + +#ifndef static_assert +#define static_assert _Static_assert +#endif + +#ifdef _DEBUG +#define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while(0) +#define DEBUG_EXPORT +#else +#define ASSERT(c) do { (void)(c); } while(0) +#define DEBUG_EXPORT static +#endif + +#define PI 3.1415926535897932384f +#define KILOBYTE (1024ULL) +#define MEGABYTE (1024ULL * 1024ULL) +#define MB(a) ((a) << 20ULL) + +#define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a)) +#define ABS(a) ((a) < 0 ? (-a) : (a)) +#define BETWEEN(x, a, b) ((x) >= (a) && (x) <= (b)) +#define CLAMP(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)) +#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) +#define SGN(a) ((a) < 0 ? (-1) : (1)) + +#define SAFE_RATIO_1(a, b) ((b) ? (a) / (b) : (a)) + +#define ISCONTROLC0(c) (BETWEEN((c), 0, 0x1F) || (c) == 0x7F) +#define ISCONTROLC1(c) (BETWEEN((c), 0x80, 0x9F)) +#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) +#define ISSPACE(c) ((c) == ' ' || (c) == '\n' || (c) == '\t') +#define ISPRINT(c) BETWEEN((c), ' ', '~') + +#define ISPOWEROFTWO(a) (((a) & ((a) - 1)) == 0) + +/* NOTE: GLFW does not sequentially number keys so switch statement will never be optimized */ +#define ENCODE_KEY(action, mod, key) (((action) << 24) | ((mod) << 16) | ((key) & 0xFFFF)) + +#define BACKLOG_SIZE (16 * MEGABYTE) +#define BACKLOG_LINES (8192UL) + +#define ALT_BACKLOG_SIZE (2 * MEGABYTE) +#define ALT_BACKLOG_LINES (1024UL) + +#define I64_MIN INT64_MIN + +typedef float f32; +typedef double f64; +typedef char c8; +typedef int8_t i8; +typedef uint8_t u8; +typedef int16_t i16; +typedef uint16_t u16; +typedef int32_t i32; +typedef uint32_t u32; +typedef uint32_t b32; +typedef int64_t i64; +typedef uint64_t u64; +typedef ptrdiff_t iptr; +typedef ptrdiff_t size; +typedef size_t usize; + +typedef struct { void *memory; size size; } MemoryBlock; + +typedef struct { u8 *beg, *end; } Arena; +typedef struct { Arena *arena; u8 *old_beg; } TempArena; + +typedef struct { size len; u8 *data; } s8; +#define s8(s) (s8){.len = ARRAY_COUNT(s) - 1, .data = (u8 *)s} + +typedef s8 os_mapped_file; + +typedef struct { + u8 *buf; + u32 cap; + u32 widx; + b32 errors; +} Stream; + +typedef struct { + size size; + u64 timestamp; +} FileStats; + +/* NOTE: virtual memory ring buffer */ +typedef struct { + size cap; + size filled; + size widx; + u8 *buf; +} RingBuf; + +typedef union { + struct { i32 x, y; }; + struct { i32 w, h; }; + i32 E[2]; +} iv2; + +typedef union { + struct { f32 x, y; }; + struct { f32 w, h; }; + f32 E[2]; +} v2; + +typedef struct { iv2 start, end; } Range; +#define INVALID_RANGE_END (iv2){.x = -1, .y = -1} + +#define INVALID_FILE (-1) +enum file_attribute { + FA_READ = 1 << 0, + FA_WRITE = 1 << 1, + FA_APPEND = 1 << 2, +}; + /* NOTE: for now we will do the callback route but this will change if we do multithreading */ #define PLATFORM_FILE_WATCH_CALLBACK_FN(name) void name(u8 *path, void *user_ctx) typedef PLATFORM_FILE_WATCH_CALLBACK_FN(platform_file_watch_callback_fn); @@ -264,4 +391,15 @@ typedef VTGL_ACTIVE_SELECTION_FN(vtgl_active_selection_fn); i32 key, i32 action, u32 modifiers) typedef VTGL_HANDLE_KEYS_FN(vtgl_handle_keys_fn); +#include "util.h" +#include "util.c" + +#include "debug.h" + +#if defined(__linux__) && (defined(__x86_64__) || defined(_M_X64)) +#include "platform_linux_amd64.c" +#else +#error Unsupported Platform! +#endif + #endif /*_VTGL_H_ */