gui shader fixes, start work on text rendering

This commit is contained in:
matthew 2025-08-11 07:36:25 +10:00
parent 70807e4a15
commit 01c4abaf1d
18 changed files with 1221 additions and 106 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
assets/textures/atlas.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -60,12 +60,12 @@ if ! [ -f build/libxxhash.a ]; then
fi
# STB_IMAGE
src="external/stb/stb_image.c"
src="external/stb/stb.c"
flags="-std=c99 -Wno-everything -Iexternal/stb -c -static"
obj="build/stb_image.o"
lib="build/libstb_image.a"
obj="build/stb.o"
lib="build/libstb.a"
if ! [ -f build/libstb_image.a ]; then
if ! [ -f build/libstb.a ]; then
$c_compiler $flags $src $out $obj
ar rcs $lib $obj
rm $obj
@ -95,3 +95,12 @@ if ! [ -f build/libcglm.a ]; then
rm $obj
fi
if ! [ -f build/atlas.png ]; then
msdf-atlas-gen -font assets/fonts/NuberNextCondensed-DemiBold.otf -dimensions 256 256 -type softmask -imageout build/atlas.png -json build/atlas.json
fi
if ! [ -f assets/textures/atlas.png ]; then
cp build/atlas.png assets/textures/atlas.png
mkdir -p assets/data
cp build/atlas.json assets/data/atlas.json
fi

View File

@ -9,9 +9,9 @@
"targetPath": "build",
"sourceFiles-linux": ["build/libvma.a", "build/libstb_image.a", "build/libm3d.a", "build/libcglm.a"],
"sourceFiles-windows": [],
"importPaths": ["src/gears", "src/shared", "src/generated", "external/xxhash", "external/inteli"],
"sourcePaths": ["src/gears", "src/shared", "src/generated", "external/xxhash", "external/inteli"],
"libs-linux": ["xcb", "X11", "X11-xcb", "vulkan", "stdc++", "xcb-xfixes", "freetype2"],
"importPaths": ["src/gears", "src/codegen", "src/shared", "external/xxhash", "external/inteli"],
"sourcePaths": ["src/gears", "src/codegen", "src/shared", "external/xxhash", "external/inteli"],
"libs-linux": ["xcb", "X11", "X11-xcb", "vulkan", "stdc++", "xcb-xfixes"],
"libs-windows": [],
"preGenerateCommands-linux": ["./build.sh", "build/Packer"],
"preGenerateCommands-windows": [],
@ -23,9 +23,9 @@
"targetType": "executable",
"targetPath": "build",
"targetName": "Packer",
"importPaths": ["src/packer", "src/shared", "src/generated", "external/xxhash", "external/inteli"],
"sourcePaths": ["src/packer", "src/shared", "src/generated", "external/xxhash", "external/inteli"],
"sourceFiles-linux": ["build/libstb_image.a", "build/libm3d.a", "build/libcglm"],
"importPaths": ["src/packer", "src/shared", "external/xxhash", "external/inteli"],
"sourcePaths": ["src/packer", "src/shared", "external/xxhash", "external/inteli"],
"sourceFiles-linux": ["build/libstb.a", "build/libm3d.a", "build/libcglm.a"],
"preGenerateCommands-linux": ["./build.sh"],
"postGenerateCommands-linux": [],
"preGenerateCommands-windows": [],

View File

@ -1,3 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

825
src/codegen/fonts.d Normal file
View File

@ -0,0 +1,825 @@
import util;
static immutable FontAtlas FONT_ATLAS = {
type: AtlasType.SoftMask,
size: 58.531250,
width: 256,
height: 256,
y_origin: YOrigin.Bottom,
em_size: 1.000000,
line_height: 1.408000,
ascender: 1.105000,
descender: -0.303000,
underline_y: -0.100000,
underline_thickness: 0.050000,
glyphs: [
{
ch: ' ',
advance: 0.207000,
},
{
ch: ',',
advance: 0.216000,
plane_left: 0.033160,
plane_bottom: -0.179391,
plane_right: 0.169840,
plane_top: 0.145222,
atlas_left: 0.033160,
atlas_bottom: -0.179391,
atlas_right: 0.169840,
atlas_top: 0.145222,
},
{
ch: '-',
advance: 0.373000,
plane_left: 0.049821,
plane_bottom: 0.230646,
plane_right: 0.323179,
plane_top: 0.350240,
atlas_left: 0.049821,
atlas_bottom: 0.230646,
atlas_right: 0.323179,
atlas_top: 0.350240,
},
{
ch: '.',
advance: 0.216000,
plane_left: 0.048203,
plane_bottom: -0.008542,
plane_right: 0.167797,
plane_top: 0.145222,
atlas_left: 0.048203,
atlas_bottom: -0.008542,
atlas_right: 0.167797,
atlas_top: 0.145222,
},
{
ch: '0',
advance: 0.467000,
plane_left: 0.019939,
plane_bottom: -0.025627,
plane_right: 0.447061,
plane_top: 0.709023,
atlas_left: 0.019939,
atlas_bottom: -0.025627,
atlas_right: 0.447061,
atlas_top: 0.709023,
},
{
ch: '1',
advance: 0.282000,
plane_left: 0.003406,
plane_bottom: -0.008542,
plane_right: 0.242594,
plane_top: 0.691938,
atlas_left: 0.003406,
atlas_bottom: -0.008542,
atlas_right: 0.242594,
atlas_top: 0.691938,
},
{
ch: '2',
advance: 0.439000,
plane_left: 0.014481,
plane_bottom: -0.008542,
plane_right: 0.424519,
plane_top: 0.709023,
atlas_left: 0.014481,
atlas_bottom: -0.008542,
atlas_right: 0.424519,
atlas_top: 0.709023,
},
{
ch: '3',
advance: 0.456000,
plane_left: 0.009939,
plane_bottom: -0.025627,
plane_right: 0.437061,
plane_top: 0.709023,
atlas_left: 0.009939,
atlas_bottom: -0.025627,
atlas_right: 0.437061,
atlas_top: 0.709023,
},
{
ch: '4',
advance: 0.466000,
plane_left: 0.011396,
plane_bottom: -0.008542,
plane_right: 0.455604,
plane_top: 0.691938,
atlas_left: 0.011396,
atlas_bottom: -0.008542,
atlas_right: 0.455604,
atlas_top: 0.691938,
},
{
ch: '5',
advance: 0.454000,
plane_left: 0.015439,
plane_bottom: -0.025627,
plane_right: 0.442561,
plane_top: 0.691938,
atlas_left: 0.015439,
atlas_bottom: -0.025627,
atlas_right: 0.442561,
atlas_top: 0.691938,
},
{
ch: '6',
advance: 0.456000,
plane_left: 0.017939,
plane_bottom: -0.025627,
plane_right: 0.445061,
plane_top: 0.709023,
atlas_left: 0.017939,
atlas_bottom: -0.025627,
atlas_right: 0.445061,
atlas_top: 0.709023,
},
{
ch: '7',
advance: 0.386000,
plane_left: 0.004066,
plane_bottom: -0.008542,
plane_right: 0.379934,
plane_top: 0.691938,
atlas_left: 0.004066,
atlas_bottom: -0.008542,
atlas_right: 0.379934,
atlas_top: 0.691938,
},
{
ch: '8',
advance: 0.464000,
plane_left: 0.018439,
plane_bottom: -0.025627,
plane_right: 0.445561,
plane_top: 0.709023,
atlas_left: 0.018439,
atlas_bottom: -0.025627,
atlas_right: 0.445561,
atlas_top: 0.709023,
},
{
ch: '9',
advance: 0.456000,
plane_left: 0.010939,
plane_bottom: -0.025627,
plane_right: 0.438061,
plane_top: 0.709023,
atlas_left: 0.010939,
atlas_bottom: -0.025627,
atlas_right: 0.438061,
atlas_top: 0.709023,
},
{
ch: ':',
advance: 0.216000,
plane_left: 0.048203,
plane_bottom: -0.008542,
plane_right: 0.167797,
plane_top: 0.521089,
atlas_left: 0.048203,
atlas_bottom: -0.008542,
atlas_right: 0.167797,
atlas_top: 0.521089,
},
{
ch: ';',
advance: 0.216000,
plane_left: 0.033160,
plane_bottom: -0.179391,
plane_right: 0.169840,
plane_top: 0.521089,
atlas_left: 0.033160,
atlas_bottom: -0.179391,
atlas_right: 0.169840,
atlas_top: 0.521089,
},
{
ch: 'A',
advance: 0.535000,
plane_left: 0.011227,
plane_bottom: -0.008542,
plane_right: 0.523773,
plane_top: 0.709023,
atlas_left: 0.011227,
atlas_bottom: -0.008542,
atlas_right: 0.523773,
atlas_top: 0.709023,
},
{
ch: 'B',
advance: 0.495000,
plane_left: 0.047439,
plane_bottom: -0.008542,
plane_right: 0.474561,
plane_top: 0.709023,
atlas_left: 0.047439,
atlas_bottom: -0.008542,
atlas_right: 0.474561,
atlas_top: 0.709023,
},
{
ch: 'C',
advance: 0.508000,
plane_left: 0.030354,
plane_bottom: -0.025627,
plane_right: 0.491646,
plane_top: 0.726108,
atlas_left: 0.030354,
atlas_bottom: -0.025627,
atlas_right: 0.491646,
atlas_top: 0.726108,
},
{
ch: 'D',
advance: 0.535000,
plane_left: 0.046854,
plane_bottom: -0.008542,
plane_right: 0.508146,
plane_top: 0.709023,
atlas_left: 0.046854,
atlas_bottom: -0.008542,
atlas_right: 0.508146,
atlas_top: 0.709023,
},
{
ch: 'E',
advance: 0.454000,
plane_left: 0.047024,
plane_bottom: -0.008542,
plane_right: 0.439976,
plane_top: 0.709023,
atlas_left: 0.047024,
atlas_bottom: -0.008542,
atlas_right: 0.439976,
atlas_top: 0.709023,
},
{
ch: 'F',
advance: 0.431000,
plane_left: 0.044066,
plane_bottom: -0.008542,
plane_right: 0.419934,
plane_top: 0.709023,
atlas_left: 0.044066,
atlas_bottom: -0.008542,
atlas_right: 0.419934,
atlas_top: 0.709023,
},
{
ch: 'G',
advance: 0.535000,
plane_left: 0.025312,
plane_bottom: -0.025627,
plane_right: 0.503688,
plane_top: 0.726108,
atlas_left: 0.025312,
atlas_bottom: -0.025627,
atlas_right: 0.503688,
atlas_top: 0.726108,
},
{
ch: 'H',
advance: 0.541000,
plane_left: 0.048896,
plane_bottom: -0.008542,
plane_right: 0.493104,
plane_top: 0.709023,
atlas_left: 0.048896,
atlas_bottom: -0.008542,
atlas_right: 0.493104,
atlas_top: 0.709023,
},
{
ch: 'I',
advance: 0.211000,
plane_left: 0.045703,
plane_bottom: -0.008542,
plane_right: 0.165297,
plane_top: 0.709023,
atlas_left: 0.045703,
atlas_bottom: -0.008542,
atlas_right: 0.165297,
atlas_top: 0.709023,
},
{
ch: 'J',
advance: 0.438000,
plane_left: 0.007024,
plane_bottom: -0.025627,
plane_right: 0.399976,
plane_top: 0.709023,
atlas_left: 0.007024,
atlas_bottom: -0.025627,
atlas_right: 0.399976,
atlas_top: 0.709023,
},
{
ch: 'K',
advance: 0.507000,
plane_left: 0.051396,
plane_bottom: -0.008542,
plane_right: 0.495604,
plane_top: 0.709023,
atlas_left: 0.051396,
atlas_bottom: -0.008542,
atlas_right: 0.495604,
atlas_top: 0.709023,
},
{
ch: 'L',
advance: 0.430000,
plane_left: 0.047566,
plane_bottom: -0.008542,
plane_right: 0.423434,
plane_top: 0.709023,
atlas_left: 0.047566,
atlas_bottom: -0.008542,
atlas_right: 0.423434,
atlas_top: 0.709023,
},
{
ch: 'M',
advance: 0.682000,
plane_left: 0.050557,
plane_bottom: -0.008542,
plane_right: 0.631443,
plane_top: 0.709023,
atlas_left: 0.050557,
atlas_bottom: -0.008542,
atlas_right: 0.631443,
atlas_top: 0.709023,
},
{
ch: 'N',
advance: 0.560000,
plane_left: 0.048854,
plane_bottom: -0.008542,
plane_right: 0.510146,
plane_top: 0.709023,
atlas_left: 0.048854,
atlas_bottom: -0.008542,
atlas_right: 0.510146,
atlas_top: 0.709023,
},
{
ch: 'O',
advance: 0.535000,
plane_left: 0.028312,
plane_bottom: -0.025627,
plane_right: 0.506688,
plane_top: 0.726108,
atlas_left: 0.028312,
atlas_bottom: -0.025627,
atlas_right: 0.506688,
atlas_top: 0.726108,
},
{
ch: 'P',
advance: 0.475000,
plane_left: 0.047481,
plane_bottom: -0.008542,
plane_right: 0.457519,
plane_top: 0.709023,
atlas_left: 0.047481,
atlas_bottom: -0.008542,
atlas_right: 0.457519,
atlas_top: 0.709023,
},
{
ch: 'Q',
advance: 0.535000,
plane_left: 0.028312,
plane_bottom: -0.145222,
plane_right: 0.506688,
plane_top: 0.726108,
atlas_left: 0.028312,
atlas_bottom: -0.145222,
atlas_right: 0.506688,
atlas_top: 0.726108,
},
{
ch: 'R',
advance: 0.500000,
plane_left: 0.046396,
plane_bottom: -0.008542,
plane_right: 0.490604,
plane_top: 0.709023,
atlas_left: 0.046396,
atlas_bottom: -0.008542,
atlas_right: 0.490604,
atlas_top: 0.709023,
},
{
ch: 'S',
advance: 0.475000,
plane_left: 0.012396,
plane_bottom: -0.025627,
plane_right: 0.456604,
plane_top: 0.726108,
atlas_left: 0.012396,
atlas_bottom: -0.025627,
atlas_right: 0.456604,
atlas_top: 0.726108,
},
{
ch: 'T',
advance: 0.466000,
plane_left: 0.010896,
plane_bottom: -0.008542,
plane_right: 0.455104,
plane_top: 0.709023,
atlas_left: 0.010896,
atlas_bottom: -0.008542,
atlas_right: 0.455104,
atlas_top: 0.709023,
},
{
ch: 'U',
advance: 0.528000,
plane_left: 0.043396,
plane_bottom: -0.025627,
plane_right: 0.487604,
plane_top: 0.709023,
atlas_left: 0.043396,
atlas_bottom: -0.025627,
atlas_right: 0.487604,
atlas_top: 0.709023,
},
{
ch: 'V',
advance: 0.522000,
plane_left: 0.004727,
plane_bottom: -0.008542,
plane_right: 0.517273,
plane_top: 0.709023,
atlas_left: 0.004727,
atlas_bottom: -0.008542,
atlas_right: 0.517273,
atlas_top: 0.709023,
},
{
ch: 'W',
advance: 0.768000,
plane_left: 0.008132,
plane_bottom: -0.008542,
plane_right: 0.759868,
plane_top: 0.709023,
atlas_left: 0.008132,
atlas_bottom: -0.008542,
atlas_right: 0.759868,
atlas_top: 0.709023,
},
{
ch: 'X',
advance: 0.513000,
plane_left: 0.008769,
plane_bottom: -0.008542,
plane_right: 0.504231,
plane_top: 0.709023,
atlas_left: 0.008769,
atlas_bottom: -0.008542,
atlas_right: 0.504231,
atlas_top: 0.709023,
},
{
ch: 'Y',
advance: 0.524000,
plane_left: 0.005727,
plane_bottom: -0.008542,
plane_right: 0.518273,
plane_top: 0.709023,
atlas_left: 0.005727,
atlas_bottom: -0.008542,
atlas_right: 0.518273,
atlas_top: 0.709023,
},
{
ch: 'Z',
advance: 0.452000,
plane_left: 0.011439,
plane_bottom: -0.008542,
plane_right: 0.438561,
plane_top: 0.709023,
atlas_left: 0.011439,
atlas_bottom: -0.008542,
atlas_right: 0.438561,
atlas_top: 0.709023,
},
{
ch: 'a',
advance: 0.427000,
plane_left: 0.009024,
plane_bottom: -0.025627,
plane_right: 0.401976,
plane_top: 0.521089,
atlas_left: 0.009024,
atlas_bottom: -0.025627,
atlas_right: 0.401976,
atlas_top: 0.521089,
},
{
ch: 'b',
advance: 0.457000,
plane_left: 0.043024,
plane_bottom: -0.025627,
plane_right: 0.435976,
plane_top: 0.709023,
atlas_left: 0.043024,
atlas_bottom: -0.025627,
atlas_right: 0.435976,
atlas_top: 0.709023,
},
{
ch: 'c',
advance: 0.423000,
plane_left: 0.018024,
plane_bottom: -0.025627,
plane_right: 0.410976,
plane_top: 0.521089,
atlas_left: 0.018024,
atlas_bottom: -0.025627,
atlas_right: 0.410976,
atlas_top: 0.521089,
},
{
ch: 'd',
advance: 0.456000,
plane_left: 0.021024,
plane_bottom: -0.025627,
plane_right: 0.413976,
plane_top: 0.709023,
atlas_left: 0.021024,
atlas_bottom: -0.025627,
atlas_right: 0.413976,
atlas_top: 0.709023,
},
{
ch: 'e',
advance: 0.430000,
plane_left: 0.021024,
plane_bottom: -0.025627,
plane_right: 0.413976,
plane_top: 0.521089,
atlas_left: 0.021024,
atlas_bottom: -0.025627,
atlas_right: 0.413976,
atlas_top: 0.521089,
},
{
ch: 'f',
advance: 0.283000,
plane_left: 0.009321,
plane_bottom: -0.008542,
plane_right: 0.282679,
plane_top: 0.726108,
atlas_left: 0.009321,
atlas_bottom: -0.008542,
atlas_right: 0.282679,
atlas_top: 0.726108,
},
{
ch: 'g',
advance: 0.448000,
plane_left: 0.020524,
plane_bottom: -0.213561,
plane_right: 0.413476,
plane_top: 0.521089,
atlas_left: 0.020524,
atlas_bottom: -0.213561,
atlas_right: 0.413476,
atlas_top: 0.521089,
},
{
ch: 'h',
advance: 0.449000,
plane_left: 0.039566,
plane_bottom: -0.008542,
plane_right: 0.415434,
plane_top: 0.709023,
atlas_left: 0.039566,
atlas_bottom: -0.008542,
atlas_right: 0.415434,
atlas_top: 0.709023,
},
{
ch: 'i',
advance: 0.184000,
plane_left: 0.032203,
plane_bottom: -0.008542,
plane_right: 0.151797,
plane_top: 0.674853,
atlas_left: 0.032203,
atlas_bottom: -0.008542,
atlas_right: 0.151797,
atlas_top: 0.674853,
},
{
ch: 'j',
advance: 0.187000,
plane_left: -0.051009,
plane_bottom: -0.213561,
plane_right: 0.154009,
plane_top: 0.674853,
atlas_left: -0.051009,
atlas_bottom: -0.213561,
atlas_right: 0.154009,
atlas_top: 0.674853,
},
{
ch: 'k',
advance: 0.434000,
plane_left: 0.042024,
plane_bottom: -0.008542,
plane_right: 0.434976,
plane_top: 0.709023,
atlas_left: 0.042024,
atlas_bottom: -0.008542,
atlas_right: 0.434976,
atlas_top: 0.709023,
},
{
ch: 'l',
advance: 0.190000,
plane_left: 0.035703,
plane_bottom: -0.008542,
plane_right: 0.155297,
plane_top: 0.709023,
atlas_left: 0.035703,
atlas_bottom: -0.008542,
atlas_right: 0.155297,
atlas_top: 0.709023,
},
{
ch: 'm',
advance: 0.690000,
plane_left: 0.039472,
plane_bottom: -0.008542,
plane_right: 0.654528,
plane_top: 0.521089,
atlas_left: 0.039472,
atlas_bottom: -0.008542,
atlas_right: 0.654528,
atlas_top: 0.521089,
},
{
ch: 'n',
advance: 0.446000,
plane_left: 0.036566,
plane_bottom: -0.008542,
plane_right: 0.412434,
plane_top: 0.521089,
atlas_left: 0.036566,
atlas_bottom: -0.008542,
atlas_right: 0.412434,
atlas_top: 0.521089,
},
{
ch: 'o',
advance: 0.442000,
plane_left: 0.015981,
plane_bottom: -0.025627,
plane_right: 0.426019,
plane_top: 0.521089,
atlas_left: 0.015981,
atlas_bottom: -0.025627,
atlas_right: 0.426019,
atlas_top: 0.521089,
},
{
ch: 'p',
advance: 0.457000,
plane_left: 0.043024,
plane_bottom: -0.213561,
plane_right: 0.435976,
plane_top: 0.521089,
atlas_left: 0.043024,
atlas_bottom: -0.213561,
atlas_right: 0.435976,
atlas_top: 0.521089,
},
{
ch: 'q',
advance: 0.455000,
plane_left: 0.021024,
plane_bottom: -0.213561,
plane_right: 0.413976,
plane_top: 0.521089,
atlas_left: 0.021024,
atlas_bottom: -0.213561,
atlas_right: 0.413976,
atlas_top: 0.521089,
},
{
ch: 'r',
advance: 0.298000,
plane_left: 0.038363,
plane_bottom: -0.008542,
plane_right: 0.294637,
plane_top: 0.521089,
atlas_left: 0.038363,
atlas_bottom: -0.008542,
atlas_right: 0.294637,
atlas_top: 0.521089,
},
{
ch: 's',
advance: 0.400000,
plane_left: 0.011066,
plane_bottom: -0.025627,
plane_right: 0.386934,
plane_top: 0.521089,
atlas_left: 0.011066,
atlas_bottom: -0.025627,
atlas_right: 0.386934,
atlas_top: 0.521089,
},
{
ch: 't',
advance: 0.293000,
plane_left: 0.004321,
plane_bottom: -0.025627,
plane_right: 0.277679,
plane_top: 0.657768,
atlas_left: 0.004321,
atlas_bottom: -0.025627,
atlas_right: 0.277679,
atlas_top: 0.657768,
},
{
ch: 'u',
advance: 0.440000,
plane_left: 0.029566,
plane_bottom: -0.025627,
plane_right: 0.405434,
plane_top: 0.521089,
atlas_left: 0.029566,
atlas_bottom: -0.025627,
atlas_right: 0.405434,
atlas_top: 0.521089,
},
{
ch: 'v',
advance: 0.419000,
plane_left: -0.004061,
plane_bottom: -0.008542,
plane_right: 0.423061,
plane_top: 0.521089,
atlas_left: -0.004061,
atlas_bottom: -0.008542,
atlas_right: 0.423061,
atlas_top: 0.521089,
},
{
ch: 'w',
advance: 0.658000,
plane_left: 0.004387,
plane_bottom: -0.008542,
plane_right: 0.653613,
plane_top: 0.521089,
atlas_left: 0.004387,
atlas_bottom: -0.008542,
atlas_right: 0.653613,
atlas_top: 0.521089,
},
{
ch: 'x',
advance: 0.412000,
plane_left: 0.000981,
plane_bottom: -0.008542,
plane_right: 0.411019,
plane_top: 0.521089,
atlas_left: 0.000981,
atlas_bottom: -0.008542,
atlas_right: 0.411019,
atlas_top: 0.521089,
},
{
ch: 'y',
advance: 0.421000,
plane_left: -0.002561,
plane_bottom: -0.213561,
plane_right: 0.424561,
plane_top: 0.521089,
atlas_left: -0.002561,
atlas_bottom: -0.213561,
atlas_right: 0.424561,
atlas_top: 0.521089,
},
{
ch: 'z',
advance: 0.383000,
plane_left: 0.002066,
plane_bottom: -0.008542,
plane_right: 0.377934,
plane_top: 0.521089,
atlas_left: 0.002066,
atlas_bottom: -0.008542,
atlas_right: 0.377934,
atlas_top: 0.521089,
},
],
};

View File

@ -9,6 +9,7 @@ import platform;
import math;
import core.stdc.math : cosf, sinf;
import std.algorithm.sorting;
import fonts;
f32 g_DELTA;
@ -77,6 +78,7 @@ struct Game
u32 ui_count;
ImageView default_tex;
ImageView font_tex;
UIPushConst ui_pc;
@ -107,8 +109,16 @@ InitGame(PlatformWindow* window)
u8[16*16*4] white_tex;
white_tex[] = u8.max;
u8[] atlas = LoadAssetData(&g.frame_arena, "textures/atlas.png");
int width, height, has_ch;
auto img = stbi_load_from_memory(atlas.ptr, cast(int)atlas.length, &width, &height, &has_ch, 4);
assert(width == FONT_ATLAS.width && height == FONT_ATLAS.height && has_ch == 1, "atlas height and width do not match");
u8[] img_slice = img[0 .. width * height];
CreateImageView(&g.rd, &g.font_tex, FONT_ATLAS.width, FONT_ATLAS.height, 1, img_slice);
CreateImageView(&g.rd, &g.default_tex, 16, 16, 4, white_tex);
WriteGUI(&g.rd, g.ui_desc_set, &g.default_tex);
WriteGUI(&g.rd, g.ui_desc_set, &g.font_tex);
GfxPipelineInfo ui_info = {
vertex_shader: "shaders/gui.vert.spv",
@ -165,7 +175,8 @@ Cycle(Game* g)
Reset(&g.frame_arena);
DrawRect(g, 200.0, 200.0, 800.0, 400.0, Vec4(0.2, 0.3, 0.7, 1.0));
DrawRect(g, 500.0, 500.0, 800.0, 800.0, Vec4(0.2, 0.3, 0.7, 1.0));
DrawText(g, 200.0, 200.0, 32.0, "Test");
BeginFrame(&g.rd);
@ -308,31 +319,66 @@ Sort(Game* g, Vec3 pos, Model* model)
}
void
DrawRect(Game* g, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col)
DrawText(Game* g, f32 x, f32 y, f32 px, string str)
{
g.ui_vertex_buf[g.ui_count].dst_start.x = p0_x;
g.ui_vertex_buf[g.ui_count].dst_start.y = p0_y;
g.ui_vertex_buf[g.ui_count].dst_end.x = p1_x;
g.ui_vertex_buf[g.ui_count].dst_end.y = p1_y;
g.ui_vertex_buf[g.ui_count].col = col;
f32 x_pos = x;
foreach(ch; str)
{
foreach(glyph; FONT_ATLAS.glyphs)
{
if (ch == glyph.ch)
{
UIVertex* v = g.ui_vertex_buf.ptr + g.ui_count;
u32 index_count = g.ui_count * 6;
f32 w = px * (glyph.plane_right - glyph.plane_left);
f32 h = px * (glyph.plane_bottom - glyph.plane_top);
f32 y_pos = px * glyph.plane_top;
g.ui_index_buf[index_count+0] = index_count+0;
g.ui_index_buf[index_count+1] = index_count+1;
g.ui_index_buf[index_count+2] = index_count+2;
g.ui_index_buf[index_count+3] = index_count+2;
g.ui_index_buf[index_count+4] = index_count+1;
g.ui_index_buf[index_count+5] = index_count+3;
v.dst_start.x = x_pos;
v.dst_start.y = y + y_pos;
v.dst_end.x = x_pos + w;
v.dst_end.y = y + h;
v.col = Vec4(1.0, 1.0, 1.0, 1.0);
x_pos += px * glyph.advance;
AddUIIndices(g);
}
}
}
}
void
AddUIIndices(Game* g)
{
g.ui_index_buf[0] = 0;
g.ui_index_buf[1] = 1;
g.ui_index_buf[2] = 2;
g.ui_index_buf[3] = 2;
g.ui_index_buf[4] = 1;
g.ui_index_buf[5] = 3;
g.ui_count += 1;
}
void
DrawRect(Game* g, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col)
{
// Y reversed
g.ui_vertex_buf[g.ui_count].dst_start.x = p0_x;
g.ui_vertex_buf[g.ui_count].dst_start.y = p1_y;
g.ui_vertex_buf[g.ui_count].dst_end.x = p1_x;
g.ui_vertex_buf[g.ui_count].dst_end.y = p0_y;
g.ui_vertex_buf[g.ui_count].col = col;
AddUIIndices(g);
}
// TODO: integrate this with vulkan again
Model
LoadModel(Game* g, string name)
{
AssetInfo info = GetAssetInfo(name);
AssetInfo info; // = GetAssetInfo(name);
u8[] data = LoadAssetData(&g.frame_arena, name);
Model model = {
@ -590,7 +636,7 @@ CopyVertex(Vec3* dst, m3dv_t* src)
void
ReadModel(Game* g, string name)
{
AssetInfo info = GetAssetInfo(name);
AssetInfo info; // = GetAssetInfo(name);
u8[] data = LoadAssetData(&g.frame_arena, name);

View File

@ -10,13 +10,9 @@ import math;
import core.stdc.string : memcpy;
// TODO:
// 1. Remove bindless (informed to be perf death)
// 2. Set up VK_AMD_shader_info
// 3. Determine how to better handle inputs
// 4. Make assets loaded from the disk in debug mode
// 5. Set up multisampling
// 6. Remove renderer.d and just move the interface into vulkan.d
// 7. Remove dynamic rendering
// 1. Determine how to better handle inputs
// 2. Set up multisampling
// 3. Replace standard library calls with nogc replacements
void main(string[] argv)
{

View File

@ -21,12 +21,17 @@ alias Pipeline = u32;
alias Attribute = VkVertexInputAttributeDescription;
alias SpecEntry = VkSpecializationMapEntry;
alias RenderPass = VkRenderPass;
alias DescSet = VkDescriptorSet;
alias DescSetLayout = VkDescriptorSetLayout;
alias PipelineLayout = VkPipelineLayout;
alias DescLayoutBinding = VkDescriptorSetLayoutBinding;
alias DescWrite = VkWriteDescriptorSet;
struct DescSet
{
VkDescriptorSet handle;
u32 dynamic_count;
}
bool g_VLAYER_SUPPORT = false;
bool g_DEBUG_PRINTF = false;
@ -352,7 +357,7 @@ struct Vulkan
Pipeline r_to_rgba_pipeline;
Pipeline rg_to_rgba_pipeline;
Pipeline rgb_to_rgba_pipeline;
VkDescriptorSet conv_desc_set;
DescSet conv_desc_set;
VkDescriptorSetLayout conv_desc_layout;
VkPipelineLayout conv_pipeline_layout;
@ -454,7 +459,7 @@ CreateDescSetLayout(Vulkan* vk, DescLayoutBinding[] bindings)
}
DescSet
AllocDescSet(Vulkan* vk, DescSetLayout layout)
AllocDescSet(Vulkan* vk, DescSetLayout layout, u32 dynamic_count = 0)
{
VkDescriptorSetAllocateInfo alloc_info = {
sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
@ -463,15 +468,17 @@ AllocDescSet(Vulkan* vk, DescSetLayout layout)
descriptorPool: vk.active_pool,
};
DescSet set;
VkResult result = vkAllocateDescriptorSets(vk.device, &alloc_info, &set);
DescSet set = {
dynamic_count: dynamic_count,
};
VkResult result = vkAllocateDescriptorSets(vk.device, &alloc_info, &set.handle);
if (result == VK_ERROR_OUT_OF_POOL_MEMORY || result == VK_ERROR_FRAGMENTED_POOL)
{
PushDescriptorPool(vk);
alloc_info.descriptorPool = vk.active_pool;
result = vkAllocateDescriptorSets(vk.device, &alloc_info, &set);
result = vkAllocateDescriptorSets(vk.device, &alloc_info, &set.handle);
VkCheckA("vkAllocateDescriptorSets failure", result); // TODO: look more into how to handle this
}
@ -530,7 +537,7 @@ InitConversionPipeline(Vulkan* vk)
VkDescriptorSetLayoutBinding[] layout_bindings = [
{ binding: 0, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_COMPUTE_BIT },
{ binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_COMPUTE_BIT },
{ binding: 1, descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: 1, stageFlags: VK_SHADER_STAGE_COMPUTE_BIT },
];
vk.conv_desc_layout = CreateDescSetLayout(vk, layout_bindings);
@ -989,7 +996,7 @@ CreateImageView(Vulkan* vk, ImageView* view, u32 w, u32 h, u32 ch, u8[] data)
ch == 2 ? vk.rg_to_rgba_pipeline :
vk.rgb_to_rgba_pipeline;
Bind(vk, pipeline, vk.conv_desc_set);
Bind(vk, pipeline, vk.conv_desc_set, true);
ConvPushConst pc = {
x: w,
@ -1375,32 +1382,54 @@ Copy(VkCommandBuffer cmd, VkImage src, VkImage dst, VkImageLayout src_layout, Vk
}
void
Bind(Vulkan* vk, Pipeline pipeline_handle, DescSet[] sets)
Bind(Vulkan* vk, Pipeline pipeline_handle, DescSet[] sets, bool compute = false)
{
assert(pipeline_handle > 0, "Bind failure: pipeline is 0");
VkCommandBuffer cmd = (compute ? vk.comp_cmd : vk.cmds[vk.frame_index]);
PipelineHandles* pipeline = vk.pipeline_handles.ptr + pipeline_handle;
BindPipeline(vk, pipeline);
BindPipeline(vk, cmd, pipeline);
u32[] offsets;
if (vk.global_set.dynamic_count > 0)
{
offsets = AllocArray!(u32)(&vk.frame_arenas[vk.frame_index], vk.global_set.dynamic_count);
}
vkCmdBindDescriptorSets(
vk.cmds[vk.frame_index],
cmd,
pipeline.type,
pipeline.layout,
0,
1,
&vk.global_set,
0,
null
&vk.global_set.handle,
cast(u32)offsets.length,
offsets.ptr
);
u32 offset_count;
VkDescriptorSet[] handles = AllocArray!(VkDescriptorSet)(&vk.frame_arenas[vk.frame_index], sets.length);
foreach(i, set; sets)
{
handles[i] = set.handle;
offset_count += set.dynamic_count;
}
if (offset_count > 0)
{
offsets = AllocArray!(u32)(&vk.frame_arenas[vk.frame_index], offset_count);
}
vkCmdBindDescriptorSets(
vk.cmds[vk.frame_index],
cmd,
pipeline.type,
pipeline.layout,
1,
cast(u32)sets.length,
sets.ptr,
0,
null
cast(u32)handles.length,
handles.ptr,
cast(u32)offsets.length,
offsets.ptr
);
}
@ -1415,68 +1444,73 @@ NewPipeline(Vulkan* vk)
}
void
Bind(Vulkan* vk, Pipeline pipeline_handle, DescSet set)
Bind(Vulkan* vk, Pipeline pipeline_handle, DescSet set, bool compute = false)
{
assert(pipeline_handle > 0, "Bind failure: pipeline is 0");
VkCommandBuffer cmd = (compute ? vk.comp_cmd : vk.cmds[vk.frame_index]);
PipelineHandles* pipeline = vk.pipeline_handles.ptr + pipeline_handle;
BindPipeline(vk, pipeline);
BindPipeline(vk, cmd, pipeline);
u32[] offsets;
if (vk.global_set.dynamic_count > 0)
{
offsets = AllocArray!(u32)(&vk.frame_arenas[vk.frame_index], vk.global_set.dynamic_count);
}
vkCmdBindDescriptorSets(
vk.cmds[vk.frame_index],
cmd,
pipeline.type,
pipeline.layout,
0,
1,
&vk.global_set,
0,
null
&vk.global_set.handle,
cast(u32)offsets.length,
offsets.ptr
);
if (set.dynamic_count > 0)
{
offsets = AllocArray!(u32)(&vk.frame_arenas[vk.frame_index], set.dynamic_count);
}
vkCmdBindDescriptorSets(
vk.cmds[vk.frame_index],
cmd,
pipeline.type,
pipeline.layout,
1,
1,
&set,
0,
null
&set.handle,
cast(u32)offsets.length,
offsets.ptr
);
}
pragma(inline): void
BindPipeline(Vulkan* vk, PipelineHandles* pipeline)
BindPipeline(Vulkan* vk, VkCommandBuffer cmd, PipelineHandles* pipeline)
{
if
(
vk.last_pipeline[vk.frame_index] == null ||
vk.last_pipeline[vk.frame_index] == VK_NULL_HANDLE ||
vk.last_pipeline[vk.frame_index] != pipeline.handle
)
{
vkCmdBindPipeline(vk.cmds[vk.frame_index], pipeline.type, pipeline.handle);
vk.last_pipeline[vk.frame_index] = pipeline.handle;
vkCmdBindPipeline(cmd, pipeline.type, pipeline.handle);
vk.last_pipeline[vk.frame_index] = pipeline.handle;
VkViewport viewport = {
x: 0.0,
y: 0.0,
width: cast(f32)vk.swapchain_extent.width,
height: cast(f32)vk.swapchain_extent.height,
minDepth: 0.0,
maxDepth: 1.0,
};
VkViewport viewport = {
x: 0.0,
y: 0.0,
width: cast(f32)vk.swapchain_extent.width,
height: cast(f32)vk.swapchain_extent.height,
minDepth: 0.0,
maxDepth: 1.0,
};
vkCmdSetViewport(vk.cmds[vk.frame_index], 0, 1, &viewport);
vkCmdSetViewport(cmd, 0, 1, &viewport);
VkRect2D scissor = {
extent: {
width: vk.swapchain_extent.width,
height: vk.swapchain_extent.height,
},
};
VkRect2D scissor = {
extent: {
width: vk.swapchain_extent.width,
height: vk.swapchain_extent.height,
},
};
vkCmdSetScissor(vk.cmds[vk.frame_index], 0, 1, &scissor);
}
vkCmdSetScissor(cmd, 0, 1, &scissor);
}
pragma(inline): void
@ -2010,6 +2044,7 @@ PushDescriptorPool(Vulkan* vk)
{ type: VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_SAMPLER, descriptorCount: 4096 },
{ type: VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, descriptorCount: 4096 },
@ -2078,7 +2113,7 @@ InitGlobalDescSet(Vulkan* vk)
VkWriteDescriptorSet write = {
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: vk.global_set,
dstSet: vk.global_set.handle,
dstBinding: 1,
descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER,
@ -2103,7 +2138,7 @@ WriteGUI(Vulkan* vk, DescSet set, ImageView* atlas)
VkWriteDescriptorSet[] writes = [
{
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: set,
dstSet: set.handle,
dstBinding: 0,
descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
@ -2124,7 +2159,7 @@ WriteDrawImageDesc(Vulkan* vk)
VkWriteDescriptorSet write = {
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: vk.global_set,
dstSet: vk.global_set.handle,
dstBinding: 0,
descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
@ -2140,11 +2175,12 @@ WriteConvDescriptor(Vulkan* vk, Buffer* buf)
VkDescriptorBufferInfo buf_info = {
buffer: buf.buffer,
range: buf.size,
offset: 0,
};
VkWriteDescriptorSet write = {
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: vk.conv_desc_set,
dstSet: vk.conv_desc_set.handle,
dstBinding: 1,
descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
@ -2164,7 +2200,7 @@ WriteConvDescriptor(Vulkan* vk, ImageView* view)
VkWriteDescriptorSet write = {
sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
dstSet: vk.conv_desc_set,
dstSet: vk.conv_desc_set.handle,
dstBinding: 0,
descriptorCount: 1,
descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,

View File

@ -6,9 +6,10 @@ import std.file;
import util;
import std.path;
import assets;
import assets_codegen;
import std.traits;
import std.algorithm.comparison;
import core.memory;
import std.json;
AssetType[string] Lookup = [
".m3d": AT.ModelM3D,
@ -24,7 +25,7 @@ string[] FILE_NAMES = [];
****** UPDATE FILE_VERSION AFTER CHANGES !! ******
**************************************************/
void main()
void main(string[] argv)
{
Log("running");
if (isDir("build"))
@ -32,8 +33,117 @@ void main()
chdir("build");
}
PackFile();
TestFile();
bool pack = false;
foreach(arg; argv)
{
if (arg == "pack")
{
pack = true;
}
}
if (pack)
{
PackFile();
TestFile();
}
CodegenFontLookup();
}
void
CodegenFontLookup()
{
mkdirRecurse("../src/codegen");
auto f = File("../src/codegen/fonts.d", "w");
string font_json = readText("atlas.json");
JSONValue j = parseJSON(font_json);
assert("atlas" in j, "atlas key not in json");
FontAtlas atlas = {
type: (j["atlas"]["type"].str == "softmask" ? AtlasType.SoftMask : AtlasType.None),
size: j["atlas"]["size"].floating,
width: cast(u32)j["atlas"]["width"].integer,
height: cast(u32)j["atlas"]["height"].integer,
y_origin: (j["atlas"]["yOrigin"].str == "bottom" ? YOrigin.Bottom : YOrigin.None),
em_size: cast(f32)j["metrics"]["emSize"].integer,
line_height: j["metrics"]["lineHeight"].floating,
ascender: j["metrics"]["ascender"].floating,
descender: j["metrics"]["descender"].floating,
underline_y: j["metrics"]["underlineY"].floating,
underline_thickness: j["metrics"]["underlineThickness"].floating,
};
foreach(val; j["glyphs"].array)
{
Glyph glyph = {
ch: cast(dchar)val["unicode"].integer,
advance: val["advance"].floating,
};
if ("planeBounds" in val)
{
glyph.plane_left = val["planeBounds"]["left"].floating;
glyph.plane_bottom = val["planeBounds"]["bottom"].floating;
glyph.plane_right = val["planeBounds"]["right"].floating;
glyph.plane_top = val["planeBounds"]["top"].floating;
glyph.atlas_left = val["planeBounds"]["left"].floating;
glyph.atlas_bottom = val["planeBounds"]["bottom"].floating;
glyph.atlas_right = val["planeBounds"]["right"].floating;
glyph.atlas_top = val["planeBounds"]["top"].floating;
}
atlas.glyphs ~= glyph;
}
f.writeln("import util;\n");
f.writeln("static immutable FontAtlas FONT_ATLAS = {");
f.writefln("\ttype: AtlasType.%s,", atlas.type);
f.writefln("\tsize: %f,", atlas.size);
f.writefln("\twidth: %d,", atlas.width);
f.writefln("\theight: %d,", atlas.height);
f.writefln("\ty_origin: YOrigin.%s,", atlas.y_origin);
f.writefln("\tem_size: %f,", atlas.em_size);
f.writefln("\tline_height: %f,", atlas.line_height);
f.writefln("\tascender: %f,", atlas.ascender);
f.writefln("\tdescender: %f,", atlas.descender);
f.writefln("\tunderline_y: %f,", atlas.underline_y);
f.writefln("\tunderline_thickness: %f,", atlas.underline_thickness);
f.writeln("\tglyphs: [");
foreach(g; atlas.glyphs)
{
f.writeln("\t\t{");
f.writefln("\t\t\tch: '%s',", g.ch);
f.writefln("\t\t\tadvance: %f,", g.advance);
if (g.plane_left > 0.0 || g.plane_right > 0.0)
{
f.writefln("\t\t\tplane_left: %f,", g.plane_left);
f.writefln("\t\t\tplane_bottom: %f,", g.plane_bottom);
f.writefln("\t\t\tplane_right: %f,", g.plane_right);
f.writefln("\t\t\tplane_top: %f,", g.plane_top);
f.writefln("\t\t\tatlas_left: %f,", g.atlas_left);
f.writefln("\t\t\tatlas_bottom: %f,", g.atlas_bottom);
f.writefln("\t\t\tatlas_right: %f,", g.atlas_right);
f.writefln("\t\t\tatlas_top: %f,", g.atlas_top);
}
f.writeln("\t\t},");
}
f.writeln("\t],");
f.writeln("};");
}
void
@ -206,7 +316,7 @@ InitModelHeader()
ModelData
ConvertModel(u8[] data)
{
assert(data.size > 4, "Model data too small for a magic number");
assert(data.length > 4, "Model data too small for a magic number");
u32 magic = *cast(u32*)(data.ptr);

View File

@ -15,5 +15,5 @@ layout (location = 0) out vec4 FragColor;
void main()
{
vec4 tex_color = texture(sampler2D(SpriteAtlas, SamplerNearest), FragData.uv);
FragColor = FragData.color * tex_color;
FragColor = FragData.color;// * tex_color;
}

View File

@ -17,10 +17,10 @@ layout (location = 0) out struct FragDataOut {
} FragData;
vec2 Vertices[4] = vec2[4](
vec2(-1.0, -1.0),
vec2(-1.0, +1.0),
vec2(+1.0, -1.0),
vec2(+1.0, +1.0)
vec2(-1.0, -1.0),
vec2(+1.0, +1.0),
vec2(+1.0, -1.0)
);
vec2 rotate(vec2 coords, float theta)

View File

@ -123,6 +123,56 @@ struct AssetInfo
bool Asset_Pack_Opened = false;
debug
{
bool g_DIR_SET = false;
void
SetDir()
{
if (exists("assets"))
{
chdir("./assets");
}
else if (exists("Gears") || exists("Gears.exe"))
{
chdir("../assets");
}
else
{
assert(false, "Unable to set directory");
}
g_DIR_SET = true;
}
u8[]
LoadAssetData(Arena* arena, string name)
{
if (!g_DIR_SET)
{
SetDir();
}
File f;
try
{
f = File(name, "rb");
}
catch (ErrnoException e)
{
assert(false, "Unable to open file");
}
u8[] mem = AllocArray!(u8)(arena, f.size());
return f.rawRead(mem);
}
}
else
{
void
OpenAssetPack()
{
@ -260,5 +310,8 @@ UnloadAssetData(string name)
}
}
}

View File

@ -6,7 +6,6 @@
# include <X11/Xlib.h>
# include <X11/keysym.h>
# include <X11/extensions/Xfixes.h>
# include <freetype2/freetype/config/ftheader.h>
#endif
#include <xmmintrin.h>

View File

@ -8,6 +8,48 @@ import core.simd;
import std.conv;
import std.string;
enum AtlasType
{
None = 0,
SoftMask,
}
enum YOrigin
{
None = 0,
Bottom,
}
struct FontAtlas
{
AtlasType type;
f32 size;
u32 width;
u32 height;
YOrigin y_origin;
f32 em_size;
f32 line_height;
f32 ascender;
f32 descender;
f32 underline_y;
f32 underline_thickness;
Glyph[] glyphs;
}
struct Glyph
{
dchar ch;
f32 advance;
f32 plane_left;
f32 plane_bottom;
f32 plane_right;
f32 plane_top;
f32 atlas_left;
f32 atlas_bottom;
f32 atlas_right;
f32 atlas_top;
}
struct TrackedSlice(T)
{
T[] slice;