vtgl

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

Commit: 3d127a8b48b808b9437a6bac542233daae212af3
Parent: 7451ad886ad12dd0bf84fa6f282433cd5711abaf
Author: Randy Palamar
Date:   Sun, 20 Oct 2024 19:09:45 -0600

do terminal layout in the fragment shader

This also properly calculates wide characters and supports
underline/strikethrough. wcwdith was removed (it doesn't even work
correctly to begin with).

debug display is broken for now but will be restored soon.

Diffstat:
MLICENSE | 24------------------------
Mbuild.sh | 6+++---
Dextern/wcwidth.c | 181-------------------------------------------------------------------------------
Mfont.c | 30+++++++++++++++---------------
Mfrag_render.glsl | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mmain.c | 10----------
Mterminal.c | 9++++-----
Mtest.c | 37++++++++++++++++++++++++++++++++++---
Mutil.c | 1-
Mutil.h | 26+++++++++++---------------
Mvert_render.glsl | 36+++++++++++++-----------------------
Mvtgl.c | 254++++++++++++++++++++++++++++++++++++-------------------------------------------
12 files changed, 262 insertions(+), 446 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -17,27 +17,3 @@ extern/utf8_decode.c has the following license: Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de> See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. - ----------------------------------------------------------------------- -extern/wcwidth.c is licensed as follows: - -Copyright © 2005-2020 Rich Felker, et al. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/build.sh b/build.sh @@ -13,12 +13,12 @@ testcflags="$cflags -O0 -ggdb -D_DEBUG -Wno-unused-function -Wno-undefined-inter [ ! -s "./config.h" ] && cp config.def.h config.h -if [ $debug ]; then +if [ ${debug} ] && [ ${debug} != "0" ]; then # Hot Reloading/Debugging - cflags="$cflags -ggdb -D_DEBUG -Wno-unused-function -Wno-undefined-internal" + cflags="$cflags -O0 -ggdb -D_DEBUG -Wno-unused-function -Wno-undefined-internal" #cflags="$cflags -fsanitize=address,undefined" - libcflags="$cflags -O0 -fPIC" + libcflags="$cflags -fPIC" libldflags="$ldflags -shared" ${cc} $libcflags vtgl.c -o vtgl.so $libldflags diff --git a/extern/wcwidth.c b/extern/wcwidth.c @@ -1,181 +0,0 @@ -static const u8 table[] = { - 16,16,16,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,16,33,16,16,16,34,35,36, - 37,38,39,40,16,16,41,16,16,16,16,16,16,16,16,16,16,16,42,43,16,16,44,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,45,16,46,47,48,49,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,50,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,51,16,16,52, - 53,16,54,55,56,16,16,16,16,16,16,57,16,16,58,16,59,60,61,62,63,64,65,66,67,68, - 69,70,16,71,72,73,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,74,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,75,76,16,16,16,77,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,78,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,79,80,16,16,16,16,16,16,16,81,16,16,16,16,16,82,83,84,16,16,16,16,16,85, - 86,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,248,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,254,255,255,255,255,191,182,0,0,0,0,0,0,0,63,0,255,23,0,0,0,0,0,248,255, - 255,0,0,1,0,0,0,0,0,0,0,0,0,0,0,192,191,159,61,0,0,0,128,2,0,0,0,255,255,255, - 7,0,0,0,0,0,0,0,0,0,0,192,255,1,0,0,0,0,0,0,248,15,32,0,0,192,251,239,62,0,0, - 0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,255,255,255,255, - 255,7,0,0,0,0,0,0,20,254,33,254,0,12,0,0,0,2,0,0,0,0,0,0,16,30,32,0,0,12,0,0, - 64,6,0,0,0,0,0,0,16,134,57,2,0,0,0,35,0,6,0,0,0,0,0,0,16,190,33,0,0,12,0,0, - 252,2,0,0,0,0,0,0,144,30,32,64,0,12,0,0,0,4,0,0,0,0,0,0,0,1,32,0,0,0,0,0,0,17, - 0,0,0,0,0,0,192,193,61,96,0,12,0,0,0,2,0,0,0,0,0,0,144,64,48,0,0,12,0,0,0,3,0, - 0,0,0,0,0,24,30,32,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,4,92,0,0,0,0,0,0,0,0,0,0,0, - 242,7,128,127,0,0,0,0,0,0,0,0,0,0,0,0,242,31,0,63,0,0,0,0,0,0,0,0,0,3,0,0,160, - 2,0,0,0,0,0,0,254,127,223,224,255,254,255,255,255,31,64,0,0,0,0,0,0,0,0,0,0,0, - 0,224,253,102,0,0,0,195,1,0,30,0,100,32,0,32,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,28,0,0,0,28,0,0,0,12,0,0,0,12,0,0,0,0,0,0,0,176,63,64,254, - 15,32,0,0,0,0,0,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,2,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,135,1,4,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 128,9,0,0,0,0,0,0,64,127,229,31,248,159,0,0,0,0,0,0,255,127,0,0,0,0,0,0,0,0, - 15,0,0,0,0,0,208,23,4,0,0,0,0,248,15,0,3,0,0,0,60,59,0,0,0,0,0,0,64,163,3,0,0, - 0,0,0,0,240,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,255,253,33,16, - 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255, - 251,0,248,0,0,0,124,0,0,0,0,0,0,223,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255, - 255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,3,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0, - 0,60,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,128,247,63,0,0,0,192,0,0,0,0,0,0,0,0,0,0,3,0,68,8,0,0,96,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,48,0,0,0,255,255,3,128,0,0,0,0,192,63,0,0,128,255,3,0, - 0,0,0,0,7,0,0,0,0,0,200,51,0,0,0,0,32,0,0, - 0,0,0,0,0,0,126,102,0,8,16,0,0,0,0,0,16,0,0,0,0,0,0,157,193,2,0,0,0,0,48,64,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,33,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,0,0,0, - 64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,255, - 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,1,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,240,0, - 0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,240,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,255,1,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,255,127,0,0,0,0,0,0,128, - 3,0,0,0,0,0,120,38,0,32,0,0,0,0,0,0,7,0,0,0,128,239,31,0,0,0,0,0,0,0,8,0,3,0, - 0,0,0,0,192,127,0,30,0,0,0,0,0,0,0,0,0,0,0,128,211,64,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,128,248,7,0,0,3,0,0,0,0,0,0,24,1,0,0,0,192,31,31,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,255,92,0,0,64,0,0,0,0,0,0,0,0,0,0,248,133,13,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,176,1,0,0,48,0,0,0,0,0,0,0,0,0,0, - 248,167,1,0,0,0,0,0,0,0,0,0,0,0,0,40,191,0,0,0,0,0,0,0,0,0,0,0,0,224,188,15,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,255,6,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,240,12,1,0,0,0,254,7,0,0,0,0,248,121,128,0,126,14,0,0,0,0,0,252, - 127,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,191,0,0,0,0,0,0,0,0,0,0,252,255, - 255,252,109,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,126,180,191,0,0,0,0,0,0,0,0,0,163,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,0,0,0,0,0,0,0,255, - 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,128,7,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,15,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,3,248,255,231,15,0,0,0,60,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, - 255,255,255,255,127,248,255,255,255,255,255,31,32,0,16,0,0,248,254,255,0,0,0, - 0,0,0,0,0,0,0,127,255,255,249,219,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,240,7,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -}; - -static const u8 wtable[] = { - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,19,16,20,21,22,16,16,16,23,16,16,24,25,26,27,28,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,29, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,30,16,16,16,16,31,16,16,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,32,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,16,16,16,33, - 34,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,35,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,36,17,17,37,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,38,39,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,40,41,42,43,44,45,46,47,16,48,49,16,16,16,16, - 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,6,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,48,0,0,0,0,0,0,255,15,0,0,0,0,128,0,0,8, - 0,2,12,0,96,48,64,16,0,0,4,44,36,32,12,0,0,0,1,0,0,0,80,184,0,0,0,0,0,0,0,224, - 0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,24,0,0,0,0,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,251,255,255,255,255,255,255,255, - 255,255,255,15,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,63,0,0,0,255,15,255,255,255,255, - 255,255,255,127,254,255,255,255,255,255,255,255,255,255,127,254,255,255,255, - 255,255,255,255,255,255,255,255,255,224,255,255,255,255,255,254,255,255,255, - 255,255,255,255,255,255,255,127,255,255,255,255,255,7,255,255,255,255,15,0, - 255,255,255,255,255,127,255,255,255,255,255,0,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0, - 0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,31,255,255,255,255,255,255,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, - 255,255,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,15,0,0,0,0,0,0,0,0,0,0,0,0,0,255,3,0,0,255,255,255,255,247,255,127,15,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,255,255,255,255,255,255,255,255,255,255, - 255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,7,0,255,255,255,127,0,0,0,0,0, - 0,7,0,240,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 15,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,64,254,7,0,0,0,0,0,0,0,0,0,0,0,0,7,0,255,255,255, - 255,255,15,255,1,3,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, - 1,224,191,255,255,255,255,255,255,255,255,223,255,255,15,0,255,255,255,255, - 255,135,15,0,255,255,17,255,255,255,255,255,255,255,255,127,253,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 159,255,255,255,255,255,255,255,63,0,120,255,255,255,0,0,4,0,0,96,0,16,0,0,0, - 0,0,0,0,0,0,0,248,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,255,255, - 255,255,255,255,255,255,63,16,39,0,0,24,240,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,255,15,0, - 0,0,224,255,255,255,255,255,255,255,255,255,255,255,255,123,252,255,255,255, - 255,231,199,255,255,255,231,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,15,7,7,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0, -}; - -static i32 wcwidth(u32 wc) -{ - if (wc < 0xffU) - return ((wc+1) & 0x7f) >= 0x21 ? 1 : wc ? -1 : 0; - if ((wc & 0xfffeffffU) < 0xfffe) { - if ((table[table[wc>>8]*32+((wc&255)>>3)]>>(wc&7))&1) - return 0; - if ((wtable[wtable[wc>>8]*32+((wc&255)>>3)]>>(wc&7))&1) - return 2; - return 1; - } - if ((wc & 0xfffe) == 0xfffe) - return -1; - if (wc-0x20000U < 0x20000) - return 2; - if (wc == 0xe0001 || wc-0xe0020U < 0x5f || wc-0xe0100U < 0xef) - return 0; - return 1; -} diff --git a/font.c b/font.c @@ -135,7 +135,7 @@ get_and_clear_glyph_cache_stats(GlyphCache *gc) } static u32 * -render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph **out_glyph, u32 *out_idx) +render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph **out_glyph) { BEGIN_TIMED_BLOCK(); GlyphCache *gc = &fa->glyph_cache; @@ -147,7 +147,6 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph u32 idx = get_glyph_entry_index(&fa->glyph_cache, packed_cp); CachedGlyph *cg = fa->glyph_cache.glyphs + idx; - *out_idx = idx; *out_glyph = cg; if (cg->uploaded_to_gpu) goto end; @@ -183,14 +182,13 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph /* NOTE: this looks weird but some 'wide' glyphs are not actually wide but still * need to be displayed as such (eg. ト). x1 can be used to determine this. */ - cg->tile_count = (u16)(width + (fa->info.w + 1) / 2) / fa->info.w; - if (cg->tile_count * fa->info.w < x1) cg->tile_count++; + cg->tile_count = (((i32)x1 - 1) / (i32)fa->info.w) + 1; + ASSERT(cg->tile_count * fa->info.w >= x1); + ASSERT(cg->tile_count >= 1); i32 out_width = fa->info.w * cg->tile_count; i32 out_size = fa->info.h * out_width; - cg->size.w = out_width; - cg->size.h = fa->info.h; ASSERT(out_width >= width); uv2 tile_coord = unpack_gpu_tile_coord(cg->gpu_tile_index); @@ -255,20 +253,22 @@ static void font_atlas_update(FontAtlas *fa, iv2 glyph_bitmap_dim) { GlyphCache *gc = &fa->glyph_cache; - mem_clear(gc->glyphs, 0, sizeof(*gc->glyphs) * gc->cache_len); - mem_clear(gc->hash_table, 0, sizeof(*gc->hash_table) * gc->cache_len); + mem_clear(gc->glyphs, 0, sizeof(*gc->glyphs) * gc->cache_len); + mem_clear(gc->hash_table, 0, sizeof(*gc->hash_table) * gc->cache_len); + mem_clear(gc->occupied_tiles, 0, sizeof(*gc->occupied_tiles) * gc->cache_len); get_and_clear_glyph_cache_stats(gc); - Font *font = &fa->fonts[0][FS_NORMAL]; + Font *font = &fa->fonts[0][FS_BOLD]; + if (!font) font = &fa->fonts[0][FS_NORMAL]; i32 x0, x1, y0, y1; stbtt_GetFontBoundingBox(&font->font_info, &x0, &y0, &x1, &y1); - f32 scale = font->stbtt_scale; - fa->info.h = scale * (y1 - y0) + 0.5; - fa->info.w = scale * (x1 - x0) + 0.5; - fa->info.baseline = -scale * y0 + 0.5; + f32 scale = font->stbtt_scale; + fa->info.h = (u32)(scale * (y1 - y0)) + 1; + fa->info.w = (u32)(scale * (x1 - x0)) + 1; + fa->info.baseline = (u32)(-scale * y0) + 1; - gc->tiles_in_x = (glyph_bitmap_dim.x - 1) / fa->info.w; - gc->tiles_in_y = (glyph_bitmap_dim.y - 1) / fa->info.h; + gc->tiles_in_x = (glyph_bitmap_dim.x - 1) / fa->info.w - 1; + gc->tiles_in_y = (glyph_bitmap_dim.y - 1) / fa->info.h - 1; ASSERT(gc->tiles_in_x && gc->tiles_in_y); ASSERT(gc->tiles_in_x * fa->info.w <= glyph_bitmap_dim.x); diff --git a/frag_render.glsl b/frag_render.glsl @@ -1,16 +1,25 @@ #version 430 core -out vec4 colour; +layout(location = 0) in vec2 pixel_coord; +layout(location = 1) in vec2 texture_coord; -in VS_OUT { - vec2 tex_coord; - flat int index; -} fs_in; +layout(location = 0) out vec4 colour; + +struct RenderCell { + uint gpu_glyph; + uint fg; + uint bg; +}; + +layout(std430, binding = 0) readonly restrict buffer ssbo_cells { + RenderCell cells[]; +}; layout(std140, binding = 0) uniform parameters { uvec2 cell_size; - uvec2 term_size; - uvec2 top_left_margin; + uvec2 term_size_in_cells; + vec2 term_size_in_pixels; + vec2 top_left_margin; uint margin_colour; float blink_parameter; @@ -21,10 +30,7 @@ layout(std140, binding = 0) uniform parameters { uint underline_max; }; -uniform sampler2DArray u_texslot; -uniform int u_charmap[512]; -uniform vec2 u_texscale[512]; -uniform uvec2 u_texcolour[512]; +layout(location = 3) uniform sampler2D u_bitmap_texture; #define ATTR_MASK 0xFFu #define ATTR_FAINT (1u << 0u) @@ -34,29 +40,61 @@ uniform uvec2 u_texcolour[512]; #define ATTR_INVISIBLE (1u << 4u) #define ATTR_STRUCK (1u << 5u) +vec2 +unpack_glyph_position(uint glyph_position) +{ + vec2 result; + result.x = glyph_position & 0xFFFFu; + result.y = glyph_position >> 16u; + return result; +} + void main() { - uint attr = u_texcolour[fs_in.index].x & ATTR_MASK; - vec3 fg = unpackUnorm4x8(u_texcolour[fs_in.index].x).wzy; - vec3 bg = unpackUnorm4x8(u_texcolour[fs_in.index].y).wzy; + uvec2 cell_index = uvec2((pixel_coord - top_left_margin) / cell_size); + vec2 cell_pos = mod((pixel_coord - top_left_margin), cell_size); - vec3 tex_coord = vec3(fs_in.tex_coord, u_charmap[fs_in.index]); - tex_coord.xy *= u_texscale[fs_in.index]; + vec3 result; + if (pixel_coord.x > top_left_margin.x && cell_index.x < term_size_in_cells.x && + pixel_coord.y > top_left_margin.y && cell_index.y < term_size_in_cells.y) + { + RenderCell cell = cells[term_size_in_cells.x * cell_index.y + cell_index.x]; - if ((attr & ATTR_FAINT) != 0) fg *= 0.5; - /* TODO: this causes a bug with reverse video */ - if ((attr & ATTR_BLINK) != 0) fg *= 0.5 * (1 + sin(blink_parameter)); + uint attr = cell.fg & ATTR_MASK; + vec3 fg = unpackUnorm4x8(cell.fg).wzy; + vec3 bg = unpackUnorm4x8(cell.bg).wzy; - if ((attr & ATTR_INVERSE) != 0) { - vec3 tmp = fg; - fg = bg; - bg = tmp; - } + vec2 glyph_pos = unpack_glyph_position(cell.gpu_glyph) * cell_size; + vec2 tex_coord = (glyph_pos + cell_pos) / vec2(textureSize(u_bitmap_texture, 0)); + + if ((attr & ATTR_FAINT) != 0) fg *= 0.5; + if ((attr & ATTR_BLINK) != 0) fg = mix(bg, fg, 0.5 * (1 + sin(blink_parameter))); + + if ((attr & ATTR_INVERSE) != 0) { + vec3 tmp = fg; + fg = bg; + bg = tmp; + } - vec4 smp = texture(u_texslot, tex_coord); - float a = u_texscale[fs_in.index].x == 0 ? 0 : smp.a; + vec4 smp = texture(u_bitmap_texture, tex_coord); + result = mix(bg, fg * smp.xyz, smp.a); - vec3 result = mix(bg, fg * smp.xyz, a); + if (((attr & ATTR_UNDERLINED) != 0) && + cell_pos.y >= underline_min && cell_pos.y < underline_max) + result = fg; - colour = vec4(result, 1); + if (((attr & ATTR_STRUCK) != 0) && + cell_pos.y >= strike_min && cell_pos.y < strike_max) + result = fg; + } else { + result = unpackUnorm4x8(margin_colour).wzy; + } + + /* NOTE: set to true to see the glyph cache texture */ + if (false) { + vec4 smp = texture(u_bitmap_texture, pixel_coord / term_size_in_pixels); + colour = smp; + } else { + colour = vec4(result, 1); + } } diff --git a/main.c b/main.c @@ -142,16 +142,6 @@ init_window(Term *t, Arena arena, iv2 window_size) glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); - glGenTextures(1, &t->gl.glyph_tex); - glBindTexture(GL_TEXTURE_2D_ARRAY, t->gl.glyph_tex); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, - MAX_FONT_SIZE, MAX_FONT_SIZE, TEXTURE_GLYPH_COUNT, - 0, GL_RED, GL_UNSIGNED_BYTE, 0); - glGenTextures(1, &t->gl.glyph_bitmap_tex); glBindTexture(GL_TEXTURE_2D, t->gl.glyph_bitmap_tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, diff --git a/terminal.c b/terminal.c @@ -1225,12 +1225,11 @@ push_line(Term *t, Line *line, Arena a) if (t->mode & TM_AUTO_WRAP && t->cursor.state & CURSOR_WRAP_NEXT) push_newline(t, 1); - i32 width; + u32 width; if (line->has_unicode) { - /* TODO: this needs to be determined from the CachedGlyph tile count - * wcwidth does not report the correct result for all characters */ - width = wcwidth(cp); - ASSERT(width != -1); + /* TODO: this is obviously complete crap but wcwidth from libc doesn't + * actually work so we must check from the rendered glyph */ + get_gpu_glyph_index(t->arena_for_frame, &t->gl, &t->fa, cp, FS_NORMAL, &width); } else { width = 1; } diff --git a/test.c b/test.c @@ -1,13 +1,39 @@ -#include "vtgl.c" +#define GL_GLEXT_PROTOTYPES 1 +#include <GLFW/glfw3.h> + +#include "util.h" +#include "config.h" + /* NOTE: stubs for stuff we aren't testing */ #undef glfwSetWindowTitle #undef glfwGetWindowTitle -void glfwSetWindowTitle(GLFWwindow *w, const char *s) {}; -const char *glfwGetWindowTitle(GLFWwindow *w) { return "test"; }; +void glfwSetWindowTitle(GLFWwindow *w, const char *s) {} +const char *glfwGetWindowTitle(GLFWwindow *w) { return "test"; } + +static void get_gpu_glyph_index(Arena, void *, void *, u32, u32, u32 *); +static GlyphCacheStats get_and_clear_glyph_cache_stats(void *p) { return (GlyphCacheStats){0}; } +static void init_font(void *a, void *b) {} + +KEYBIND_FN(copy) { return 0; } +KEYBIND_FN(paste) { return 0; } +KEYBIND_FN(scroll) { return 0; } +KEYBIND_FN(zoom) { return 0; } + +#include "terminal.c" +#include "debug.c" #include <string.h> /* memcmp */ +#include <wchar.h> /* wcwidth */ + +static void +get_gpu_glyph_index(Arena a, void *b, void *c, u32 cp, u32 d, u32 *width) +{ + /* TODO: this is wrong but will have to do for these tests */ + *width = wcwidth(cp); + ASSERT(*width != -1); +} #define ESC(a) s8("\x1B"#a) #define CSI(a) ESC([a) @@ -251,6 +277,11 @@ static TEST_FN(working_ringbuffer) static u32 failure_count; +#ifdef _DEBUG +/* NOTE: shut up compiler warning that can't be disabled */ +DebugRecord debug_records[__COUNTER__]; +#endif + int main(void) { diff --git a/util.c b/util.c @@ -191,4 +191,3 @@ utf8_encode(u32 cp) } #include "extern/utf8_decode.c" -#include "extern/wcwidth.c" diff --git a/util.h b/util.h @@ -185,11 +185,6 @@ typedef struct { #define GL_RENDER_UNIFORMS \ X(Pmat) \ - X(charmap) \ - X(texcolour) \ - X(texscale) \ - X(texslot) \ - X(vertoff) \ X(vertscale) #define GL_POST_UNIFORMS \ @@ -225,9 +220,10 @@ enum shader_stages { typedef struct { uv2 cell_size; - uv2 term_size; + uv2 term_size_in_cells; + v2 term_size_in_pixels; - uv2 top_left_margin; + v2 top_left_margin; u32 margin_colour; f32 blink_parameter; @@ -237,6 +233,8 @@ typedef struct { u32 underline_min; u32 underline_max; + + u32 _pad[2]; } ShaderParameters; typedef struct { @@ -268,10 +266,14 @@ typedef struct { u32 flags; u32 mode; - - u32 glyph_tex; } GLCtx; +typedef struct { + u32 gpu_glyph; + u32 fg; + u32 bg; +} RenderCell; + /* NOTE: This must match the number in the shaders & the number glyphs in * the gpu glyph cache. By doing this we ensure that filling a single push buffer * will not evict a needed glyph texture from the GPU */ @@ -287,7 +289,6 @@ typedef struct { #define MIN_FONT_SIZE 8 #define MAX_FONT_SIZE 128 -#define TEXTURE_GLYPH_COUNT PUSH_BUFFER_CAP enum conversion_status { CR_FAILURE, CR_SUCCESS }; struct conversion_result { @@ -339,7 +340,6 @@ typedef struct { i32 baseline; } FontInfo; -#define GLYPH_CACHE_LEN PUSH_BUFFER_CAP typedef struct { /* distance to shift glyph from bounding box origin */ iv2 delta; @@ -351,10 +351,6 @@ typedef struct { u32 cp; u32 next_with_same_hash; u32 gpu_tile_index; - union { - struct { u16 h, w; }; - struct { u16 x, y; }; - } size; u16 prev, next; u16 uploaded_to_gpu; u16 tile_count; diff --git a/vert_render.glsl b/vert_render.glsl @@ -1,31 +1,21 @@ -#version 400 core +#version 430 core -in vec2 position; +layout(location = 0) in vec2 position; -uniform mat4 u_Pmat; -uniform vec2 u_vertscale[512]; -uniform vec2 u_vertoff[512]; +layout(location = 0) out vec2 pixel_coord; +layout(location = 1) out vec2 texture_coord; -out VS_OUT { - vec2 tex_coord; - flat int index; -} vs_out; +layout(location = 0) uniform mat4 u_Pmat; +layout(location = 1) uniform vec2 u_vertscale; void main() { - vec2 scale = u_vertscale[gl_InstanceID]; - vec2 offset = u_vertoff[gl_InstanceID]; + vec2 pos = position.xy; + vec2 scale = u_vertscale; - mat4 transform = mat4( - scale.x, 0, 0, 0, - 0, scale.y, 0, 0, - 0, 0, 1, 0, - offset.x, offset.y, 0, 1 - ); - - gl_Position = u_Pmat * transform * vec4(position, 0.0, 1.0); - - vs_out.tex_coord = position; - vs_out.tex_coord.y = 1.0 - vs_out.tex_coord.y; - vs_out.index = gl_InstanceID; + texture_coord = pos; + pixel_coord = pos; + pixel_coord.y = 1 - pixel_coord.y; + pixel_coord *= scale; + gl_Position = u_Pmat * vec4(pos * scale, 0.0, 1.0); } diff --git a/vtgl.c b/vtgl.c @@ -6,6 +6,10 @@ #include "config.h" #include "font.c" + +/* TODO this should be removed */ +static u32 get_gpu_glyph_index(Arena, GLCtx *, FontAtlas *, u32, enum face_style, u32 *); + #include "terminal.c" #ifdef _DEBUG @@ -66,21 +70,6 @@ get_occupied_size(Term *t) } static v2 -get_terminal_top_left(Term *t) -{ - /* NOTE: There is trade-off here: you can center the usable area which looks good but - * causes the contents to jump around when resizing; or you can only consider the global - * padding and have the contents fixed while resizing. We are choosing the former! */ - /* IMPORTANT: Assume the glyphs already have subpixel rendering so cells must be aligned - * on pixels. No harm if they don't but if they do and we don't align on pixels they - * will look like crap. */ - v2 os = get_occupied_size(t); - v2 delta = {.x = t->gl.window_size.w - os.w, .y = t->gl.window_size.h - os.h}; - v2 result = {.x = (u32)(delta.x / 2), .y = (u32)(t->gl.window_size.h - delta.y / 2)}; - return result; -} - -static v2 get_terminal_bot_left(Term *t) { v2 os = get_occupied_size(t); @@ -92,7 +81,8 @@ get_terminal_bot_left(Term *t) static void resize(Term *t) { - v2 ws = t->gl.window_size; + GLCtx *gl = &t->gl; + v2 ws = gl->window_size; ws.w -= 2 * g_term_margin.w; ws.h -= 2 * g_term_margin.h; @@ -109,13 +99,29 @@ resize(Term *t) if (!equal_uv2(old_size, t->size)) { os_alloc_framebuffer(&t->views[0].fb, t->size.h, t->size.w); os_alloc_framebuffer(&t->views[1].fb, t->size.h, t->size.w); - t->gl.flags |= NEEDS_FULL_REFILL; + gl->flags |= NEEDS_FULL_REFILL; } os_set_term_size(t->child, t->size.h, t->size.w, ws.w, ws.h); - t->gl.flags &= ~NEEDS_RESIZE; -} + u32 buffer_size = t->size.w * t->size.h * sizeof(RenderCell); + glDeleteBuffers(1, &gl->render_shader_ssbo); + glGenBuffers(1, &gl->render_shader_ssbo); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, gl->render_shader_ssbo); + glBufferData(GL_SHADER_STORAGE_BUFFER, buffer_size, 0, GL_DYNAMIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, gl->render_shader_ssbo); + + ShaderParameters *sp = &gl->shader_parameters; + sp->cell_size = (uv2){.w = cs.w, .h = cs.h}; + sp->top_left_margin = g_term_margin; + sp->margin_colour = g_colours.data[g_colours.bgidx].rgba; + //sp->margin_colour = 0x7f003f00; + + sp->term_size_in_pixels = gl->window_size; + sp->term_size_in_cells = t->size; + + gl->flags &= ~NEEDS_RESIZE; +} static void update_uniforms(Term *t, enum shader_stages stage) { @@ -140,13 +146,6 @@ update_uniforms(Term *t, enum shader_stages stage) set_projection_matrix(&t->gl); } -static uv2 -unpack_gpu_glyph_index(u32 gpu_glyph_index) -{ - uv2 result = {.x = gpu_glyph_index & 0xFFFF, .y = gpu_glyph_index >> 16}; - return result; -} - static iv2 get_gpu_texture_position(v2 cs, uv2 gpu_position) { @@ -154,24 +153,14 @@ get_gpu_texture_position(v2 cs, uv2 gpu_position) return result; } -static i32 -get_gpu_glyph_index(Arena a, GLCtx *gl, FontAtlas *fa, u32 codepoint, enum face_style style, uv2 *glyph_size) +static u32 +get_gpu_glyph_index(Arena a, GLCtx *gl, FontAtlas *fa, u32 codepoint, enum face_style style, u32 *tiles) { - u32 depth_idx; CachedGlyph *cg; - u32 *data = render_glyph(&a, fa, codepoint, style, &cg, &depth_idx); - *glyph_size = (uv2){.h = cg->size.h, .w = cg->size.w}; + u32 *data = render_glyph(&a, fa, codepoint, style, &cg); if (data) { - ASSERT(depth_idx); - glBindTexture(GL_TEXTURE_2D_ARRAY, gl->glyph_tex); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, depth_idx, - glyph_size->w, glyph_size->h, 1, GL_RGBA, - GL_UNSIGNED_BYTE, data); cg->uploaded_to_gpu = 1; - /* TODO: this will be bound beforehand */ - glBindTexture(GL_TEXTURE_2D, gl->glyph_bitmap_tex); - uv2 gpu_position = unpack_gpu_tile_coord(cg->gpu_tile_index); v2 cell_size = get_cell_size(fa); iv2 glyph_position = get_gpu_texture_position(cell_size, gpu_position); @@ -181,13 +170,13 @@ get_gpu_glyph_index(Arena a, GLCtx *gl, FontAtlas *fa, u32 codepoint, enum face_ glTexSubImage2D(GL_TEXTURE_2D, 0, glyph_position.x, glyph_position.y, cell_size.w * cg->tile_count, cell_size.h, GL_RGBA, GL_UNSIGNED_BYTE, data); - - glBindTexture(GL_TEXTURE_2D_ARRAY, gl->glyph_tex); } ASSERT(cg->uploaded_to_gpu); - return depth_idx; + *tiles = cg->tile_count; + return cg->gpu_tile_index; } +#if 0 static void flush_render_push_buffer(RenderPushBuffer *rpb, GLCtx *gl) { @@ -243,119 +232,99 @@ draw_rectangle(RenderPushBuffer *rpb, GLCtx *gl, Rect r, Colour colour) { push_char(rpb, gl, r.size, r.pos, (v2){0}, (uv2){.y = colour.rgba}, 0); } +#endif -static void -push_cell(RenderPushBuffer *rpb, GLCtx *gl, FontAtlas *fa, Arena a, Cell c, Rect r) -{ - BEGIN_TIMED_BLOCK(); - u32 idx = get_render_push_buffer_idx(rpb, gl, 2); - - ASSERT(c.cp); - uv2 g_size; - i32 depth_idx = get_gpu_glyph_index(a, gl, fa, c.cp, c.style.attr & FS_MASK, &g_size); - - rpb->vertscales[idx + 0] = r.size; - rpb->vertscales[idx + 1] = (v2){.x = g_size.w, .y = g_size.h}; - - rpb->vertoffsets[idx + 0] = r.pos; - rpb->vertoffsets[idx + 1] = r.pos; - - rpb->texscales[idx + 0] = (v2){0}; - rpb->texscales[idx + 1] = (v2){ - .x = g_size.w / (f32)MAX_FONT_SIZE, - .y = g_size.h / (f32)MAX_FONT_SIZE, - }; - - rpb->charmap[idx + 0] = depth_idx; - rpb->charmap[idx + 1] = depth_idx; - - CellStyle cs = c.style; - - u32 attr = (cs.attr & ATTR_SHADER_MASK) >> 2; - u32 fg = (cs.fg.rgba & 0xFFFFFF00) | attr; - u32 bg = (cs.bg.rgba & 0xFFFFFF00) | attr; - u32 rmask = (gl->mode & WIN_MODE_REVERSE)? REVERSE_VIDEO_MASK : 0; - - rpb->texcolours[idx + 0].x = fg ^ rmask; - rpb->texcolours[idx + 0].y = bg ^ rmask; - rpb->texcolours[idx + 1].x = fg ^ rmask; - rpb->texcolours[idx + 1].y = bg ^ rmask; - END_TIMED_BLOCK(); -} - -static void -push_cell_row(RenderPushBuffer *rpb, GLCtx *gl, FontAtlas *fa, Arena a, Cell *row, u32 len, - b32 inverse, Rect cr) -{ - ASSERT(inverse == 0 || inverse == 1); - v2 cs = cr.size; - v2 csw = {.w = cs.w * 2, .h = cs.h}; - for (u32 c = 0; c < len; c++) { - Cell cell = row[c]; - if (cell.style.attr & ATTR_WDUMMY) - continue; - if (cell.style.attr & ATTR_WIDE) cr.size = csw; - else cr.size = cs; - cell.style.attr ^= inverse * ATTR_INVERSE; - push_cell(rpb, gl, fa, a, cell, cr); - cr.pos.x += cr.size.w; - } -} - +/* TODO: this is outdated */ /* NOTE: In this program we render to an offscreen render target that is later drawn * to the screen as a full window quad. Therefore render_framebuffer must take care * to handle all necessary padding (window and cell). Outside of here everyone should * simply care about the terminal in terms of rows and columns (t->size). */ static void -render_framebuffer(Term *t, RenderPushBuffer *rpb) +render_framebuffer(Term *t, RenderCell *render_buf) { BEGIN_TIMED_BLOCK(); - v2 tl = get_terminal_top_left(t); - v2 cs = get_cell_size(&t->fa); - Rect cr = {.pos = {.x = tl.x, .y = tl.y - cs.h}, .size = cs}; - TermView *tv = t->views + t->view_idx; + /* NOTE: draw whole framebuffer */ - for (u32 r = 0; r < t->size.h; r++) { - push_cell_row(rpb, &t->gl, &t->fa, t->arena_for_frame, tv->fb.rows[r], t->size.w, 0, cr); - cr.pos.y -= cs.h; + for (u32 row = 0; row < t->size.h; row++) { + for (u32 col = 0; col < t->size.w; col++) { + Cell *c = &tv->fb.rows[row][col]; + RenderCell *rc = render_buf + (row * t->size.w + col); + + u32 tiles; + rc->gpu_glyph = get_gpu_glyph_index(t->arena_for_frame, &t->gl, &t->fa, + c->cp, c->style.attr & FS_MASK, &tiles); + + u32 attr = (c->style.attr & ATTR_SHADER_MASK) >> 2; + u32 rmask = (t->gl.mode & WIN_MODE_REVERSE)? REVERSE_VIDEO_MASK : 0; + rc->fg = ((c->style.fg.rgba & 0xFFFFFF00) | attr) ^ rmask; + rc->bg = ((c->style.bg.rgba & 0xFFFFFF00) | attr) ^ rmask; + + /* TODO: there is probably a better way to do this */ + if (tiles > 1) { + for (u32 i = 1; i < tiles; i++) { + rc[i].gpu_glyph = rc->gpu_glyph + i; + rc[i].fg = rc->fg; + rc[i].bg = rc->bg; + } + col += tiles - 1; + } + } } /* NOTE: draw selection if active */ - /* TODO: combine with original push_cell? */ if (is_valid_range(t->selection.range)) { Range sel = t->selection.range; iv2 curs = sel.start; iv2 end = sel.end; - cr.pos = (v2){.x = tl.x + cs.w * curs.x, .y = tl.h - cs.h * (curs.y + 1)}; /* NOTE: do full rows first */ for (; curs.y < end.y; curs.y++) { - u32 len = t->size.w - curs.x - 1; - push_cell_row(rpb, &t->gl, &t->fa, t->arena_for_frame, - tv->fb.rows[curs.y] + curs.x, len, 1, cr); - curs.x = 0; - cr.pos.x = tl.x; - cr.pos.y -= cs.h; + for (u32 i = curs.x; i < t->size.w; i++) { + Cell *c = &tv->fb.rows[curs.y][i]; + RenderCell *rc = render_buf + curs.y * t->size.w + i; + rc->fg ^= (ATTR_INVERSE >> 2); + if (c->style.attr & ATTR_WIDE) { + for (u32 j = 1; c[j].style.attr & ATTR_WDUMMY; j++) { + rc[j].fg ^= (ATTR_INVERSE >> 2); + i++; + } + } + } + curs.x = 0; } /* NOTE: do the last row */ - push_cell_row(rpb, &t->gl, &t->fa, t->arena_for_frame, tv->fb.rows[curs.y] + curs.x, - end.x - curs.x + 1, 1, cr); + for (u32 i = curs.x; i <= end.x; i++) { + Cell *c = &tv->fb.rows[curs.y][i]; + RenderCell *rc = render_buf + curs.y * t->size.w + i; + rc->fg ^= (ATTR_INVERSE >> 2); + if (c->style.attr & ATTR_WIDE) { + for (u32 j = 1; c[j].style.attr & ATTR_WDUMMY; j++) { + rc[j].fg ^= (ATTR_INVERSE >> 2); + i++; + } + } + } } /* NOTE: draw cursor */ if (!(t->gl.mode & WIN_MODE_HIDECURSOR) && t->scroll_offset == 0) { - iv2 curs = t->cursor.pos; - cr.pos = (v2){.x = tl.x + cs.w * curs.x, .y = tl.h - cs.h * (curs.y + 1)}; - Cell cursor = tv->fb.rows[t->cursor.pos.y][t->cursor.pos.x]; - - ASSERT(!(cursor.style.attr & ATTR_WDUMMY)); - if (cursor.style.attr & ATTR_WIDE) - cr.size.w *= 2; - cursor.style.attr ^= ATTR_INVERSE; + iv2 curs = t->cursor.pos; + Cell *c = &tv->fb.rows[curs.y][curs.x]; + RenderCell *rc = render_buf + curs.y * t->size.w + curs.x; + ASSERT(!(c->style.attr & ATTR_WDUMMY)); + + rc->fg ^= (ATTR_INVERSE >> 2); if ((t->mode & TM_ALTSCREEN) == 0) - cursor.style.attr |= ATTR_BLINK; - push_cell(rpb, &t->gl, &t->fa, t->arena_for_frame, cursor, cr); + rc->fg |= (ATTR_BLINK >> 2); + + if (c->style.attr & ATTR_WIDE) { + for (u32 j = 1; c[j].style.attr & ATTR_WDUMMY; j++) { + rc[j].fg ^= (ATTR_INVERSE >> 2); + if ((t->mode & TM_ALTSCREEN) == 0) + rc[j].fg |= (ATTR_BLINK >> 2); + } + } } END_TIMED_BLOCK(); @@ -799,28 +768,35 @@ do_terminal(Term *t, f32 dt) update_selection(t); + u32 cell_count = t->size.h * t->size.w; /* NOTE: this must be done every frame since we have time varying parameters */ - RenderPushBuffer *rpb = alloc(&t->arena_for_frame, RenderPushBuffer, 1); + RenderCell *render_buf = alloc(&t->arena_for_frame, RenderCell, cell_count); + render_framebuffer(t, render_buf); + + ShaderParameters *sp = &t->gl.shader_parameters; + sp->blink_parameter += 2 * PI * g_blink_speed * dt_for_frame; + if (sp->blink_parameter > 2 * PI) sp->blink_parameter -= 2 * PI; + sp->strike_min = (u32)(t->fa.info.baseline + 0.40 * t->fa.info.h); + sp->strike_max = (u32)(t->fa.info.baseline + 0.48 * t->fa.info.h); + sp->underline_min = (u32)(0.94 * t->fa.info.h); + sp->underline_max = t->fa.info.h; + glUseProgram(t->gl.programs[SHADER_RENDER]); glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb); - glUniform1i(t->gl.render.texslot, 0); clear_colour(t->gl.mode & WIN_MODE_REVERSE); - /* TODO: turns instead of PI nonsense */ - ShaderParameters *sp = &t->gl.shader_parameters; - sp->blink_parameter += 2 * PI * g_blink_speed * dt_for_frame; - if (sp->blink_parameter > 2 * PI) sp->blink_parameter -= 2 * PI; + glUniform2fv(t->gl.render.vertscale, 1, t->gl.window_size.E); glBindBuffer(GL_UNIFORM_BUFFER, t->gl.render_shader_ubo); glBindBufferBase(GL_UNIFORM_BUFFER, 0, t->gl.render_shader_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(*sp), sp); - render_framebuffer(t, rpb); - flush_render_push_buffer(rpb, &t->gl); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, t->gl.render_shader_ssbo); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, t->gl.render_shader_ssbo); + glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, cell_count * sizeof(*render_buf), render_buf); - draw_debug_overlay(t, rpb); - flush_render_push_buffer(rpb, &t->gl); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); static f32 param = 0; static f32 p_scale = 1; @@ -843,6 +819,7 @@ do_terminal(Term *t, f32 dt) #ifdef _DEBUG DebugRecord debug_records[__COUNTER__]; +#if 0 static void draw_debug_overlay(Term *t, RenderPushBuffer *rpb) { @@ -937,3 +914,4 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) r.size.h = ws.h - r.pos.y; } #endif +#endif