1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#include "common.glsl"
// The position of the glyph in the texture (x, y)
layout(location = 0) in uvec2 glyph_pos;
// The size of the glyph in the texture (w, h)
layout(location = 1) in uvec2 glyph_size;
// The left and top bearings for the glyph (x, y)
layout(location = 2) in ivec2 bearings;
// The grid coordinates (x, y) where x < columns and y < rows
layout(location = 3) in uvec2 grid_pos;
// The color of the rendered text glyph.
layout(location = 4) in uvec4 color;
// Which atlas this glyph is in.
layout(location = 5) in uint atlas;
// Misc glyph properties.
layout(location = 6) in uint glyph_bools;
// Values `atlas` can take.
const uint ATLAS_GRAYSCALE = 0u;
const uint ATLAS_COLOR = 1u;
// Masks for the `glyph_bools` attribute
const uint NO_MIN_CONTRAST = 1u;
const uint IS_CURSOR_GLYPH = 2u;
out CellTextVertexOut {
flat uint atlas;
flat vec4 color;
flat vec4 bg_color;
vec2 tex_coord;
} out_data;
layout(binding = 1, std430) readonly buffer bg_cells {
uint bg_colors[];
};
void main() {
uvec2 grid_size = unpack2u16(grid_size_packed_2u16);
uvec2 cursor_pos = unpack2u16(cursor_pos_packed_2u16);
bool cursor_wide = (bools & CURSOR_WIDE) != 0;
bool use_linear_blending = (bools & USE_LINEAR_BLENDING) != 0;
// Convert the grid x, y into world space x, y by accounting for cell size
vec2 cell_pos = cell_size * vec2(grid_pos);
int vid = gl_VertexID;
// We use a triangle strip with 4 vertices to render quads,
// so we determine which corner of the cell this vertex is in
// based on the vertex ID.
//
// 0 --> 1
// | .'|
// | / |
// | L |
// 2 --> 3
//
// 0 = top-left (0, 0)
// 1 = top-right (1, 0)
// 2 = bot-left (0, 1)
// 3 = bot-right (1, 1)
vec2 corner;
corner.x = float(vid == 1 || vid == 3);
corner.y = float(vid == 2 || vid == 3);
out_data.atlas = atlas;
// === Grid Cell ===
// +X
// 0,0--...->
// |
// . offset.x = bearings.x
// +Y. .|.
// . | |
// | cell_pos -> +-------+ _.
// v ._| |_. _|- offset.y = cell_size.y - bearings.y
// | | .###. | |
// | | #...# | |
// glyph_size.y -+ | ##### | |
// | | #.... | +- bearings.y
// |_| .#### | |
// | |_|
// +-------+
// |_._|
// |
// glyph_size.x
//
// In order to get the top left of the glyph, we compute an offset based on
// the bearings. The Y bearing is the distance from the bottom of the cell
// to the top of the glyph, so we subtract it from the cell height to get
// the y offset. The X bearing is the distance from the left of the cell
// to the left of the glyph, so it works as the x offset directly.
vec2 size = vec2(glyph_size);
vec2 offset = vec2(bearings);
offset.y = cell_size.y - offset.y;
// Calculate the final position of the cell which uses our glyph size
// and glyph offset to create the correct bounding box for the glyph.
cell_pos = cell_pos + size * corner + offset;
gl_Position = projection_matrix * vec4(cell_pos.x, cell_pos.y, 0.0f, 1.0f);
// Calculate the texture coordinate in pixels. This is NOT normalized
// (between 0.0 and 1.0), and does not need to be, since the texture will
// be sampled with pixel coordinate mode.
out_data.tex_coord = vec2(glyph_pos) + vec2(glyph_size) * corner;
// Get our color. We always fetch a linearized version to
// make it easier to handle minimum contrast calculations.
out_data.color = load_color(color, true);
// Get the BG color
out_data.bg_color = load_color(
unpack4u8(bg_colors[grid_pos.y * grid_size.x + grid_pos.x]),
true
);
// Blend it with the global bg color
vec4 global_bg = load_color(
unpack4u8(bg_color_packed_4u8),
true
);
out_data.bg_color += global_bg * vec4(1.0 - out_data.bg_color.a);
// If we have a minimum contrast, we need to check if we need to
// change the color of the text to ensure it has enough contrast
// with the background.
if (min_contrast > 1.0f && (glyph_bools & NO_MIN_CONTRAST) == 0) {
// Ensure our minimum contrast
out_data.color = contrasted_color(min_contrast, out_data.color, out_data.bg_color);
}
// Check if current position is under cursor (including wide cursor)
bool is_cursor_pos = ((grid_pos.x == cursor_pos.x) || (cursor_wide && (grid_pos.x == (cursor_pos.x + 1)))) && (grid_pos.y == cursor_pos.y);
// If this cell is the cursor cell, but we're not processing
// the cursor glyph itself, then we need to change the color.
if ((glyph_bools & IS_CURSOR_GLYPH) == 0 && is_cursor_pos) {
out_data.color = load_color(unpack4u8(cursor_color_packed_4u8), use_linear_blending);
}
}
|