mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-10-05 01:16:33 +00:00
render text from our terminal!
This commit is contained in:
@@ -1,8 +1,19 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
|
in vec2 glyph_tex_coords;
|
||||||
|
|
||||||
/// The background color for this cell.
|
/// The background color for this cell.
|
||||||
flat in vec4 bg_color;
|
flat in vec4 bg_color;
|
||||||
|
|
||||||
|
/// Font texture
|
||||||
|
uniform sampler2D text;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_FragColor = bg_color;
|
int background = 0;
|
||||||
|
if (background == 1) {
|
||||||
|
gl_FragColor = bg_color;
|
||||||
|
} else {
|
||||||
|
float a = texture(text, glyph_tex_coords).r;
|
||||||
|
gl_FragColor = vec4(bg_color.rgb, bg_color.a*a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,17 +3,31 @@
|
|||||||
// The grid coordinates (x, y) where x < columns and y < rows
|
// The grid coordinates (x, y) where x < columns and y < rows
|
||||||
layout (location = 0) in vec2 grid_coord;
|
layout (location = 0) in vec2 grid_coord;
|
||||||
|
|
||||||
|
// Position of the glyph in the texture.
|
||||||
|
layout (location = 1) in vec2 glyph_pos;
|
||||||
|
|
||||||
|
// Width/height of the glyph
|
||||||
|
layout (location = 2) in vec2 glyph_size;
|
||||||
|
|
||||||
|
// Offset of the top-left corner of the glyph when rendered in a rect.
|
||||||
|
layout (location = 3) in vec2 glyph_offset;
|
||||||
|
|
||||||
// The background color for this cell in RGBA (0 to 1.0)
|
// The background color for this cell in RGBA (0 to 1.0)
|
||||||
layout (location = 1) in vec4 bg_color_in;
|
layout (location = 4) in vec4 bg_color_in;
|
||||||
|
|
||||||
// The background color for this cell in RGBA (0 to 1.0)
|
// The background color for this cell in RGBA (0 to 1.0)
|
||||||
flat out vec4 bg_color;
|
flat out vec4 bg_color;
|
||||||
|
|
||||||
|
// The x/y coordinate for the glyph representing the font.
|
||||||
|
out vec2 glyph_tex_coords;
|
||||||
|
|
||||||
|
uniform sampler2D text;
|
||||||
uniform vec2 cell_size;
|
uniform vec2 cell_size;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Top-left cell coordinates converted to world space
|
// Top-left cell coordinates converted to world space
|
||||||
|
// Example: (1,0) with a 30 wide cell is converted to (30,0)
|
||||||
vec2 cell_pos = cell_size * grid_coord;
|
vec2 cell_pos = cell_size * grid_coord;
|
||||||
|
|
||||||
// Turn the cell position into a vertex point depending on the
|
// Turn the cell position into a vertex point depending on the
|
||||||
@@ -21,11 +35,39 @@ void main() {
|
|||||||
// for each corner of the cell. We can use gl_VertexID to determine
|
// for each corner of the cell. We can use gl_VertexID to determine
|
||||||
// which one we're looking at. Using this, we can use 1 or 0 to keep
|
// which one we're looking at. Using this, we can use 1 or 0 to keep
|
||||||
// or discard the value for the vertex.
|
// or discard the value for the vertex.
|
||||||
|
//
|
||||||
|
// 0 = top-right
|
||||||
|
// 1 = bot-right
|
||||||
|
// 2 = bot-left
|
||||||
|
// 3 = top-left
|
||||||
vec2 position;
|
vec2 position;
|
||||||
position.x = (gl_VertexID == 0 || gl_VertexID == 1) ? 1. : 0.;
|
position.x = (gl_VertexID == 0 || gl_VertexID == 1) ? 1. : 0.;
|
||||||
position.y = (gl_VertexID == 0 || gl_VertexID == 3) ? 0. : 1.;
|
position.y = (gl_VertexID == 0 || gl_VertexID == 3) ? 0. : 1.;
|
||||||
cell_pos = cell_pos + cell_size * position;
|
|
||||||
|
|
||||||
gl_Position = projection * vec4(cell_pos, 1.0, 1.0);
|
int background = 0;
|
||||||
bg_color = vec4(bg_color_in.rgb / 255.0, 1.0);
|
if (background == 1) {
|
||||||
|
// Calculate the final position of our cell in world space.
|
||||||
|
// We have to add our cell size since our vertices are offset
|
||||||
|
// one cell up and to the left. (Do the math to verify yourself)
|
||||||
|
cell_pos = cell_pos + cell_size * position;
|
||||||
|
|
||||||
|
gl_Position = projection * vec4(cell_pos, 0.0, 1.0);
|
||||||
|
bg_color = vec4(bg_color_in.rgb / 255.0, 1.0);
|
||||||
|
} else {
|
||||||
|
// TODO: why?
|
||||||
|
vec2 glyph_offset_calc = glyph_offset;
|
||||||
|
glyph_offset_calc.y = cell_size.y - glyph_offset.y;
|
||||||
|
|
||||||
|
// Calculate the final position of the cell.
|
||||||
|
cell_pos = cell_pos + glyph_size * position + glyph_offset_calc;
|
||||||
|
gl_Position = projection * vec4(cell_pos, 0.0, 1.0);
|
||||||
|
|
||||||
|
// Calculate our texture coordinate
|
||||||
|
ivec2 text_size = textureSize(text, 0);
|
||||||
|
vec2 glyph_tex_size = glyph_size / text_size.xy;
|
||||||
|
glyph_tex_coords = glyph_pos + glyph_tex_size * position;
|
||||||
|
|
||||||
|
// This is used to color the font for now.
|
||||||
|
bg_color = vec4(bg_color_in.rgb / 255.0, 1.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -191,6 +191,7 @@ fn f26dot6ToFloat(v: ftc.FT_F26Dot6) f32 {
|
|||||||
fn codepoint(v: anytype) u32 {
|
fn codepoint(v: anytype) u32 {
|
||||||
// We need a UTF32 codepoint for freetype
|
// We need a UTF32 codepoint for freetype
|
||||||
return switch (@TypeOf(v)) {
|
return switch (@TypeOf(v)) {
|
||||||
|
u32 => v,
|
||||||
comptime_int, u8 => @intCast(u32, v),
|
comptime_int, u8 => @intCast(u32, v),
|
||||||
[]const u8 => @intCast(u32, try std.unicode.utfDecode(v)),
|
[]const u8 => @intCast(u32, try std.unicode.utfDecode(v)),
|
||||||
else => @compileError("invalid codepoint type"),
|
else => @compileError("invalid codepoint type"),
|
||||||
|
78
src/Grid.zig
78
src/Grid.zig
@@ -29,6 +29,10 @@ program: gl.Program,
|
|||||||
vao: gl.VertexArray,
|
vao: gl.VertexArray,
|
||||||
ebo: gl.Buffer,
|
ebo: gl.Buffer,
|
||||||
vbo: gl.Buffer,
|
vbo: gl.Buffer,
|
||||||
|
texture: gl.Texture,
|
||||||
|
|
||||||
|
/// The font atlas.
|
||||||
|
font_atlas: FontAtlas,
|
||||||
|
|
||||||
/// The raw structure that maps directly to the buffer sent to the vertex shader.
|
/// The raw structure that maps directly to the buffer sent to the vertex shader.
|
||||||
const GPUCell = struct {
|
const GPUCell = struct {
|
||||||
@@ -36,6 +40,18 @@ const GPUCell = struct {
|
|||||||
grid_col: u16,
|
grid_col: u16,
|
||||||
grid_row: u16,
|
grid_row: u16,
|
||||||
|
|
||||||
|
/// vec2 glyph_pos
|
||||||
|
glyph_x: f32,
|
||||||
|
glyph_y: f32,
|
||||||
|
|
||||||
|
/// vec2 glyph_size
|
||||||
|
glyph_width: u32,
|
||||||
|
glyph_height: u32,
|
||||||
|
|
||||||
|
/// vec2 glyph_size
|
||||||
|
glyph_offset_x: i32,
|
||||||
|
glyph_offset_y: i32,
|
||||||
|
|
||||||
/// vec4 bg_color_in
|
/// vec4 bg_color_in
|
||||||
bg_r: u8,
|
bg_r: u8,
|
||||||
bg_g: u8,
|
bg_g: u8,
|
||||||
@@ -47,9 +63,9 @@ pub fn init(alloc: Allocator) !Grid {
|
|||||||
// Initialize our font atlas. We will initially populate the
|
// Initialize our font atlas. We will initially populate the
|
||||||
// font atlas with all the visible ASCII characters since they are common.
|
// font atlas with all the visible ASCII characters since they are common.
|
||||||
var atlas = try Atlas.init(alloc, 512);
|
var atlas = try Atlas.init(alloc, 512);
|
||||||
defer atlas.deinit(alloc);
|
errdefer atlas.deinit(alloc);
|
||||||
var font = try FontAtlas.init(atlas);
|
var font = try FontAtlas.init(atlas);
|
||||||
defer font.deinit(alloc);
|
errdefer font.deinit(alloc);
|
||||||
try font.loadFaceFromMemory(face_ttf, 30);
|
try font.loadFaceFromMemory(face_ttf, 30);
|
||||||
|
|
||||||
// Load all visible ASCII characters and build our cell width based on
|
// Load all visible ASCII characters and build our cell width based on
|
||||||
@@ -117,11 +133,42 @@ pub fn init(alloc: Allocator) !Grid {
|
|||||||
var offset: usize = 0;
|
var offset: usize = 0;
|
||||||
try vbobind.attributeAdvanced(0, 2, gl.c.GL_UNSIGNED_SHORT, false, @sizeOf(GPUCell), offset);
|
try vbobind.attributeAdvanced(0, 2, gl.c.GL_UNSIGNED_SHORT, false, @sizeOf(GPUCell), offset);
|
||||||
offset += 2 * @sizeOf(u16);
|
offset += 2 * @sizeOf(u16);
|
||||||
try vbobind.attributeAdvanced(1, 4, gl.c.GL_UNSIGNED_BYTE, false, @sizeOf(GPUCell), offset);
|
try vbobind.attributeAdvanced(1, 2, gl.c.GL_FLOAT, false, @sizeOf(GPUCell), offset);
|
||||||
|
offset += 2 * @sizeOf(f32);
|
||||||
|
try vbobind.attributeAdvanced(2, 2, gl.c.GL_UNSIGNED_INT, false, @sizeOf(GPUCell), offset);
|
||||||
|
offset += 2 * @sizeOf(u32);
|
||||||
|
try vbobind.attributeAdvanced(3, 2, gl.c.GL_INT, false, @sizeOf(GPUCell), offset);
|
||||||
|
offset += 2 * @sizeOf(i32);
|
||||||
|
try vbobind.attributeAdvanced(4, 4, gl.c.GL_UNSIGNED_BYTE, false, @sizeOf(GPUCell), offset);
|
||||||
try vbobind.enableAttribArray(0);
|
try vbobind.enableAttribArray(0);
|
||||||
try vbobind.enableAttribArray(1);
|
try vbobind.enableAttribArray(1);
|
||||||
|
try vbobind.enableAttribArray(2);
|
||||||
|
try vbobind.enableAttribArray(3);
|
||||||
|
try vbobind.enableAttribArray(4);
|
||||||
try vbobind.attributeDivisor(0, 1);
|
try vbobind.attributeDivisor(0, 1);
|
||||||
try vbobind.attributeDivisor(1, 1);
|
try vbobind.attributeDivisor(1, 1);
|
||||||
|
try vbobind.attributeDivisor(2, 1);
|
||||||
|
try vbobind.attributeDivisor(3, 1);
|
||||||
|
try vbobind.attributeDivisor(4, 1);
|
||||||
|
|
||||||
|
// Build our texture
|
||||||
|
const tex = try gl.Texture.create();
|
||||||
|
errdefer tex.destroy();
|
||||||
|
const texbind = try tex.bind(.@"2D");
|
||||||
|
try texbind.parameter(.WrapS, gl.c.GL_CLAMP_TO_EDGE);
|
||||||
|
try texbind.parameter(.WrapT, gl.c.GL_CLAMP_TO_EDGE);
|
||||||
|
try texbind.parameter(.MinFilter, gl.c.GL_LINEAR);
|
||||||
|
try texbind.parameter(.MagFilter, gl.c.GL_LINEAR);
|
||||||
|
try texbind.image2D(
|
||||||
|
0,
|
||||||
|
.Red,
|
||||||
|
@intCast(c_int, atlas.size),
|
||||||
|
@intCast(c_int, atlas.size),
|
||||||
|
0,
|
||||||
|
.Red,
|
||||||
|
.UnsignedByte,
|
||||||
|
atlas.data.ptr,
|
||||||
|
);
|
||||||
|
|
||||||
return Grid{
|
return Grid{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
@@ -132,10 +179,15 @@ pub fn init(alloc: Allocator) !Grid {
|
|||||||
.vao = vao,
|
.vao = vao,
|
||||||
.ebo = ebo,
|
.ebo = ebo,
|
||||||
.vbo = vbo,
|
.vbo = vbo,
|
||||||
|
.texture = tex,
|
||||||
|
.font_atlas = font,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Grid) void {
|
pub fn deinit(self: *Grid) void {
|
||||||
|
self.font_atlas.atlas.deinit(self.alloc);
|
||||||
|
self.font_atlas.deinit(self.alloc);
|
||||||
|
self.texture.destroy();
|
||||||
self.vbo.destroy();
|
self.vbo.destroy();
|
||||||
self.ebo.destroy();
|
self.ebo.destroy();
|
||||||
self.vao.destroy();
|
self.vao.destroy();
|
||||||
@@ -179,14 +231,21 @@ pub fn updateCells(self: *Grid, term: Terminal) !void {
|
|||||||
|
|
||||||
for (term.screen.items) |line, y| {
|
for (term.screen.items) |line, y| {
|
||||||
for (line.items) |cell, x| {
|
for (line.items) |cell, x| {
|
||||||
_ = cell;
|
// Get our glyph
|
||||||
|
const glyph = try self.font_atlas.addGlyph(self.alloc, cell.char);
|
||||||
|
|
||||||
self.cells.appendAssumeCapacity(.{
|
self.cells.appendAssumeCapacity(.{
|
||||||
.grid_col = @intCast(u16, x),
|
.grid_col = @intCast(u16, x),
|
||||||
.grid_row = @intCast(u16, y),
|
.grid_row = @intCast(u16, y),
|
||||||
.bg_r = @intCast(u8, @mod(x * y, 255)),
|
.glyph_x = glyph.s0,
|
||||||
.bg_g = @intCast(u8, @mod(x, 255)),
|
.glyph_y = glyph.t0,
|
||||||
.bg_b = @intCast(u8, 255 - @mod(x, 255)),
|
.glyph_width = glyph.width,
|
||||||
|
.glyph_height = glyph.height,
|
||||||
|
.glyph_offset_x = glyph.offset_x,
|
||||||
|
.glyph_offset_y = glyph.offset_y,
|
||||||
|
.bg_r = 0xFF,
|
||||||
|
.bg_g = 0xA5,
|
||||||
|
.bg_b = 0,
|
||||||
.bg_a = 255,
|
.bg_a = 255,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -237,6 +296,11 @@ pub fn render(self: Grid) !void {
|
|||||||
defer binding.unbind();
|
defer binding.unbind();
|
||||||
try binding.setData(self.cells.items, .StaticDraw);
|
try binding.setData(self.cells.items, .StaticDraw);
|
||||||
|
|
||||||
|
// Bind our texture
|
||||||
|
try gl.Texture.active(gl.c.GL_TEXTURE0);
|
||||||
|
var texbind = try self.texture.bind(.@"2D");
|
||||||
|
defer texbind.unbind();
|
||||||
|
|
||||||
try gl.drawElementsInstanced(
|
try gl.drawElementsInstanced(
|
||||||
gl.c.GL_TRIANGLES,
|
gl.c.GL_TRIANGLES,
|
||||||
6,
|
6,
|
||||||
|
Reference in New Issue
Block a user