mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-01-03 03:52:38 +00:00
Move shaders into the renderer dir
This commit is contained in:
@@ -201,7 +201,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
||||
};
|
||||
|
||||
// Initialize our shader (MTLLibrary)
|
||||
const library = try initLibrary(device, @embedFile("../shaders/cell.metal"));
|
||||
const library = try initLibrary(device, @embedFile("shaders/cell.metal"));
|
||||
const pipeline_state = try initPipelineState(device, library);
|
||||
const texture_greyscale = try initAtlasTexture(device, &options.font_group.atlas_greyscale);
|
||||
const texture_color = try initAtlasTexture(device, &options.font_group.atlas_color);
|
||||
@@ -399,8 +399,8 @@ pub fn render(
|
||||
defer critical.screen.deinit();
|
||||
|
||||
// @autoreleasepool {}
|
||||
const pool = objc_autoreleasePoolPush();
|
||||
defer objc_autoreleasePoolPop(pool);
|
||||
const pool = objc.AutoreleasePool.init();
|
||||
defer pool.deinit();
|
||||
|
||||
// If we're resizing, then we have to update a bunch of things...
|
||||
if (critical.screen_size) |_| {
|
||||
@@ -1285,5 +1285,3 @@ const MTLSize = extern struct {
|
||||
};
|
||||
|
||||
extern "c" fn MTLCreateSystemDefaultDevice() ?*anyopaque;
|
||||
extern "c" fn objc_autoreleasePoolPush() ?*anyopaque;
|
||||
extern "c" fn objc_autoreleasePoolPop(?*anyopaque) void;
|
||||
|
||||
@@ -168,8 +168,8 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
|
||||
|
||||
// Create our shader
|
||||
const program = try gl.Program.createVF(
|
||||
@embedFile("../shaders/cell.v.glsl"),
|
||||
@embedFile("../shaders/cell.f.glsl"),
|
||||
@embedFile("shaders/cell.v.glsl"),
|
||||
@embedFile("shaders/cell.f.glsl"),
|
||||
);
|
||||
|
||||
// Set our cell dimensions
|
||||
|
||||
105
src/renderer/shaders/cell.f.glsl
Normal file
105
src/renderer/shaders/cell.f.glsl
Normal file
@@ -0,0 +1,105 @@
|
||||
#version 330 core
|
||||
|
||||
in vec2 glyph_tex_coords;
|
||||
flat in uint mode;
|
||||
|
||||
// The color for this cell. If this is a background pass this is the
|
||||
// background color. Otherwise, this is the foreground color.
|
||||
flat in vec4 color;
|
||||
|
||||
// The position of the cells top-left corner.
|
||||
flat in vec2 screen_cell_pos;
|
||||
|
||||
// Position the fragment coordinate to the upper left
|
||||
layout(origin_upper_left) in vec4 gl_FragCoord;
|
||||
|
||||
// Must declare this output for some versions of OpenGL.
|
||||
layout(location = 0) out vec4 out_FragColor;
|
||||
|
||||
// Font texture
|
||||
uniform sampler2D text;
|
||||
uniform sampler2D text_color;
|
||||
|
||||
// Dimensions of the cell
|
||||
uniform vec2 cell_size;
|
||||
|
||||
// See vertex shader
|
||||
const uint MODE_BG = 1u;
|
||||
const uint MODE_FG = 2u;
|
||||
const uint MODE_FG_COLOR = 7u;
|
||||
const uint MODE_CURSOR_RECT = 3u;
|
||||
const uint MODE_CURSOR_RECT_HOLLOW = 4u;
|
||||
const uint MODE_CURSOR_BAR = 5u;
|
||||
const uint MODE_UNDERLINE = 6u;
|
||||
const uint MODE_STRIKETHROUGH = 8u;
|
||||
|
||||
void main() {
|
||||
float a;
|
||||
|
||||
switch (mode) {
|
||||
case MODE_BG:
|
||||
out_FragColor = color;
|
||||
break;
|
||||
|
||||
case MODE_FG:
|
||||
a = texture(text, glyph_tex_coords).r;
|
||||
out_FragColor = vec4(color.rgb, color.a*a);
|
||||
break;
|
||||
|
||||
case MODE_FG_COLOR:
|
||||
out_FragColor = texture(text_color, glyph_tex_coords);
|
||||
break;
|
||||
|
||||
case MODE_CURSOR_RECT:
|
||||
out_FragColor = color;
|
||||
break;
|
||||
|
||||
case MODE_CURSOR_RECT_HOLLOW:
|
||||
// Okay so yeah this is probably horrendously slow and a shader
|
||||
// should never do this, but we only ever render a cursor for ONE
|
||||
// rectangle so we take the slowdown for that one.
|
||||
|
||||
// Default to no color.
|
||||
out_FragColor = vec4(0., 0., 0., 0.);
|
||||
|
||||
// We subtracted one from cell size because our coordinates start at 0.
|
||||
// So a width of 50 means max pixel of 49.
|
||||
vec2 cell_size_coords = cell_size - 1;
|
||||
|
||||
// Apply padding
|
||||
vec2 padding = vec2(1.,1.);
|
||||
cell_size_coords = cell_size_coords - (padding * 2);
|
||||
vec2 screen_cell_pos_padded = screen_cell_pos + padding;
|
||||
|
||||
// Convert our frag coord to offset of this cell. We have to subtract
|
||||
// 0.5 because the frag coord is in center pixels.
|
||||
vec2 cell_frag_coord = gl_FragCoord.xy - screen_cell_pos_padded - 0.5;
|
||||
|
||||
// If the frag coords are in the bounds, then we color it.
|
||||
const float eps = 0.1;
|
||||
if (cell_frag_coord.x >= 0 && cell_frag_coord.y >= 0 &&
|
||||
cell_frag_coord.x <= cell_size_coords.x &&
|
||||
cell_frag_coord.y <= cell_size_coords.y) {
|
||||
if (abs(cell_frag_coord.x) < eps ||
|
||||
abs(cell_frag_coord.x - cell_size_coords.x) < eps ||
|
||||
abs(cell_frag_coord.y) < eps ||
|
||||
abs(cell_frag_coord.y - cell_size_coords.y) < eps) {
|
||||
out_FragColor = color;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MODE_CURSOR_BAR:
|
||||
out_FragColor = color;
|
||||
break;
|
||||
|
||||
case MODE_UNDERLINE:
|
||||
out_FragColor = color;
|
||||
break;
|
||||
|
||||
case MODE_STRIKETHROUGH:
|
||||
out_FragColor = color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
268
src/renderer/shaders/cell.metal
Normal file
268
src/renderer/shaders/cell.metal
Normal file
@@ -0,0 +1,268 @@
|
||||
using namespace metal;
|
||||
|
||||
// The possible modes that a shader can take.
|
||||
enum Mode : uint8_t {
|
||||
MODE_BG = 1u,
|
||||
MODE_FG = 2u,
|
||||
MODE_FG_COLOR = 7u,
|
||||
MODE_CURSOR_RECT = 3u,
|
||||
MODE_CURSOR_RECT_HOLLOW = 4u,
|
||||
MODE_CURSOR_BAR = 5u,
|
||||
MODE_UNDERLINE = 6u,
|
||||
MODE_STRIKETHROUGH = 8u,
|
||||
};
|
||||
|
||||
struct Uniforms {
|
||||
float4x4 projection_matrix;
|
||||
float2 cell_size;
|
||||
float underline_position;
|
||||
float underline_thickness;
|
||||
float strikethrough_position;
|
||||
float strikethrough_thickness;
|
||||
};
|
||||
|
||||
struct VertexIn {
|
||||
// The mode for this cell.
|
||||
uint8_t mode [[ attribute(0) ]];
|
||||
|
||||
// The grid coordinates (x, y) where x < columns and y < rows
|
||||
float2 grid_pos [[ attribute(1) ]];
|
||||
|
||||
// The width of the cell in cells (i.e. 2 for double-wide).
|
||||
uint8_t cell_width [[ attribute(6) ]];
|
||||
|
||||
// The color. For BG modes, this is the bg color, for FG modes this is
|
||||
// the text color. For styles, this is the color of the style.
|
||||
uchar4 color [[ attribute(5) ]];
|
||||
|
||||
// The fields below are present only when rendering text.
|
||||
|
||||
// The position of the glyph in the texture (x,y)
|
||||
uint2 glyph_pos [[ attribute(2) ]];
|
||||
|
||||
// The size of the glyph in the texture (w,h)
|
||||
uint2 glyph_size [[ attribute(3) ]];
|
||||
|
||||
// The left and top bearings for the glyph (x,y)
|
||||
int2 glyph_offset [[ attribute(4) ]];
|
||||
};
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[ position ]];
|
||||
float2 cell_size;
|
||||
uint8_t mode;
|
||||
float4 color;
|
||||
float2 tex_coord;
|
||||
};
|
||||
|
||||
vertex VertexOut uber_vertex(
|
||||
unsigned int vid [[ vertex_id ]],
|
||||
VertexIn input [[ stage_in ]],
|
||||
constant Uniforms &uniforms [[ buffer(1) ]]
|
||||
) {
|
||||
// Convert the grid x,y into world space x, y by accounting for cell size
|
||||
float2 cell_pos = uniforms.cell_size * input.grid_pos;
|
||||
|
||||
// Scaled cell size for the cell width
|
||||
float2 cell_size_scaled = uniforms.cell_size;
|
||||
cell_size_scaled.x = cell_size_scaled.x * input.cell_width;
|
||||
|
||||
// Turn the cell position into a vertex point depending on the
|
||||
// vertex ID. Since we use instanced drawing, we have 4 vertices
|
||||
// for each corner of the cell. We can use vertex ID to determine
|
||||
// which one we're looking at. Using this, we can use 1 or 0 to keep
|
||||
// or discard the value for the vertex.
|
||||
//
|
||||
// 0 = top-right
|
||||
// 1 = bot-right
|
||||
// 2 = bot-left
|
||||
// 3 = top-left
|
||||
float2 position;
|
||||
position.x = (vid == 0 || vid == 1) ? 1.0f : 0.0f;
|
||||
position.y = (vid == 0 || vid == 3) ? 0.0f : 1.0f;
|
||||
|
||||
VertexOut out;
|
||||
out.mode = input.mode;
|
||||
out.cell_size = uniforms.cell_size;
|
||||
out.color = float4(input.color) / 255.0f;
|
||||
switch (input.mode) {
|
||||
case MODE_BG:
|
||||
// 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_scaled * position;
|
||||
|
||||
out.position = uniforms.projection_matrix * float4(cell_pos.x, cell_pos.y, 0.0f, 1.0f);
|
||||
break;
|
||||
|
||||
case MODE_FG:
|
||||
case MODE_FG_COLOR: {
|
||||
float2 glyph_size = float2(input.glyph_size);
|
||||
float2 glyph_offset = float2(input.glyph_offset);
|
||||
|
||||
// If the glyph is larger than our cell, we need to downsample it.
|
||||
// The "+ 3" here is to give some wiggle room for fonts that are
|
||||
// BARELY over it.
|
||||
float2 glyph_size_downsampled = glyph_size;
|
||||
if (glyph_size_downsampled.y > cell_size_scaled.y + 2) {
|
||||
// Magic 0.9 and 1.1 are padding to make emoji look better
|
||||
glyph_size_downsampled.y = cell_size_scaled.y * 0.9;
|
||||
glyph_size_downsampled.x = glyph_size.x * (glyph_size_downsampled.y / glyph_size.y);
|
||||
glyph_offset.y = glyph_offset.y * 1.1 * (glyph_size_downsampled.y / glyph_size.y);
|
||||
}
|
||||
|
||||
// The glyph_offset.y is the y bearing, a y value that when added
|
||||
// to the baseline is the offset (+y is up). Our grid goes down.
|
||||
// So we flip it with `cell_size.y - glyph_offset.y`.
|
||||
glyph_offset.y = cell_size_scaled.y - glyph_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 + glyph_size_downsampled * position + glyph_offset;
|
||||
out.position = uniforms.projection_matrix * float4(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 must be done in the fragment shader.
|
||||
out.tex_coord = float2(input.glyph_pos) + float2(input.glyph_size) * position;
|
||||
break;
|
||||
}
|
||||
|
||||
case MODE_CURSOR_RECT:
|
||||
// Same as background since we're taking up the whole cell.
|
||||
cell_pos = cell_pos + cell_size_scaled * position;
|
||||
|
||||
out.position = uniforms.projection_matrix * float4(cell_pos, 0.0f, 1.0);
|
||||
break;
|
||||
|
||||
case MODE_CURSOR_RECT_HOLLOW:
|
||||
// Top-left position of this cell is needed for the hollow rect.
|
||||
out.tex_coord = cell_pos;
|
||||
|
||||
// Same as background since we're taking up the whole cell.
|
||||
cell_pos = cell_pos + cell_size_scaled * position;
|
||||
out.position = uniforms.projection_matrix * float4(cell_pos, 0.0f, 1.0);
|
||||
break;
|
||||
|
||||
case MODE_CURSOR_BAR: {
|
||||
// Make the bar a smaller version of our cell
|
||||
float2 bar_size = float2(uniforms.cell_size.x * 0.2, uniforms.cell_size.y);
|
||||
|
||||
// Same as background since we're taking up the whole cell.
|
||||
cell_pos = cell_pos + bar_size * position;
|
||||
|
||||
out.position = uniforms.projection_matrix * float4(cell_pos, 0.0f, 1.0);
|
||||
break;
|
||||
}
|
||||
|
||||
case MODE_UNDERLINE: {
|
||||
// Underline Y value is just our thickness
|
||||
float2 underline_size = float2(cell_size_scaled.x, uniforms.underline_thickness);
|
||||
|
||||
// Position the underline where we are told to
|
||||
float2 underline_offset = float2(cell_size_scaled.x, uniforms.underline_position);
|
||||
|
||||
// Go to the bottom of the cell, take away the size of the
|
||||
// underline, and that is our position. We also float it slightly
|
||||
// above the bottom.
|
||||
cell_pos = cell_pos + underline_offset - (underline_size * position);
|
||||
|
||||
out.position = uniforms.projection_matrix * float4(cell_pos, 0.0f, 1.0);
|
||||
break;
|
||||
}
|
||||
|
||||
case MODE_STRIKETHROUGH: {
|
||||
// Strikethrough Y value is just our thickness
|
||||
float2 strikethrough_size = float2(cell_size_scaled.x, uniforms.strikethrough_thickness);
|
||||
|
||||
// Position the strikethrough where we are told to
|
||||
float2 strikethrough_offset = float2(cell_size_scaled.x, uniforms.strikethrough_position);
|
||||
|
||||
// Go to the bottom of the cell, take away the size of the
|
||||
// strikethrough, and that is our position. We also float it slightly
|
||||
// above the bottom.
|
||||
cell_pos = cell_pos + strikethrough_offset - (strikethrough_size * position);
|
||||
|
||||
out.position = uniforms.projection_matrix * float4(cell_pos, 0.0f, 1.0);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 uber_fragment(
|
||||
VertexOut in [[ stage_in ]],
|
||||
texture2d<float> textureGreyscale [[ texture(0) ]],
|
||||
texture2d<float> textureColor [[ texture(1) ]]
|
||||
) {
|
||||
constexpr sampler textureSampler(address::clamp_to_edge, filter::linear);
|
||||
|
||||
switch (in.mode) {
|
||||
case MODE_BG:
|
||||
return in.color;
|
||||
|
||||
case MODE_FG: {
|
||||
// Normalize the texture coordinates to [0,1]
|
||||
float2 size = float2(textureGreyscale.get_width(), textureGreyscale.get_height());
|
||||
float2 coord = in.tex_coord / size;
|
||||
|
||||
float a = textureGreyscale.sample(textureSampler, coord).r;
|
||||
return float4(in.color.rgb, in.color.a * a);
|
||||
}
|
||||
|
||||
case MODE_FG_COLOR: {
|
||||
// Normalize the texture coordinates to [0,1]
|
||||
float2 size = float2(textureColor.get_width(), textureColor.get_height());
|
||||
float2 coord = in.tex_coord / size;
|
||||
return textureColor.sample(textureSampler, coord);
|
||||
}
|
||||
|
||||
case MODE_CURSOR_RECT:
|
||||
return in.color;
|
||||
|
||||
case MODE_CURSOR_RECT_HOLLOW: {
|
||||
// Okay so yeah this is probably horrendously slow and a shader
|
||||
// should never do this, but we only ever render a cursor for ONE
|
||||
// rectangle so we take the slowdown for that one.
|
||||
|
||||
// We subtracted one from cell size because our coordinates start at 0.
|
||||
// So a width of 50 means max pixel of 49.
|
||||
float2 cell_size_coords = in.cell_size - 1;
|
||||
|
||||
// Apply padding
|
||||
float2 padding = float2(1.0f, 1.0f);
|
||||
cell_size_coords = cell_size_coords - (padding * 2);
|
||||
float2 screen_cell_pos_padded = in.tex_coord + padding;
|
||||
|
||||
// Convert our frag coord to offset of this cell. We have to subtract
|
||||
// 0.5 because the frag coord is in center pixels.
|
||||
float2 cell_frag_coord = in.position.xy - screen_cell_pos_padded - 0.5;
|
||||
|
||||
// If the frag coords are in the bounds, then we color it.
|
||||
const float eps = 0.1;
|
||||
if (cell_frag_coord.x >= 0 && cell_frag_coord.y >= 0 &&
|
||||
cell_frag_coord.x <= cell_size_coords.x &&
|
||||
cell_frag_coord.y <= cell_size_coords.y) {
|
||||
if (abs(cell_frag_coord.x) < eps ||
|
||||
abs(cell_frag_coord.x - cell_size_coords.x) < eps ||
|
||||
abs(cell_frag_coord.y) < eps ||
|
||||
abs(cell_frag_coord.y - cell_size_coords.y) < eps) {
|
||||
return in.color;
|
||||
}
|
||||
}
|
||||
|
||||
// Default to no color.
|
||||
return float4(0.0f);
|
||||
}
|
||||
|
||||
case MODE_CURSOR_BAR:
|
||||
return in.color;
|
||||
|
||||
case MODE_UNDERLINE:
|
||||
return in.color;
|
||||
|
||||
case MODE_STRIKETHROUGH:
|
||||
return in.color;
|
||||
}
|
||||
}
|
||||
235
src/renderer/shaders/cell.v.glsl
Normal file
235
src/renderer/shaders/cell.v.glsl
Normal file
@@ -0,0 +1,235 @@
|
||||
#version 330 core
|
||||
|
||||
// These are the possible modes that "mode" can be set to. This is
|
||||
// used to multiplex multiple render modes into a single shader.
|
||||
//
|
||||
// NOTE: this must be kept in sync with the fragment shader
|
||||
const uint MODE_BG = 1u;
|
||||
const uint MODE_FG = 2u;
|
||||
const uint MODE_FG_COLOR = 7u;
|
||||
const uint MODE_CURSOR_RECT = 3u;
|
||||
const uint MODE_CURSOR_RECT_HOLLOW = 4u;
|
||||
const uint MODE_CURSOR_BAR = 5u;
|
||||
const uint MODE_UNDERLINE = 6u;
|
||||
const uint MODE_STRIKETHROUGH = 8u;
|
||||
|
||||
// The grid coordinates (x, y) where x < columns and y < rows
|
||||
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)
|
||||
layout (location = 4) in vec4 fg_color_in;
|
||||
|
||||
// The background color for this cell in RGBA (0 to 1.0)
|
||||
layout (location = 5) in vec4 bg_color_in;
|
||||
|
||||
// The mode of this shader. The mode determines what fields are used,
|
||||
// what the output will be, etc. This shader is capable of executing in
|
||||
// multiple "modes" so that we can share some logic and so that we can draw
|
||||
// the entire terminal grid in a single GPU pass.
|
||||
layout (location = 6) in uint mode_in;
|
||||
|
||||
// The width in cells of this item.
|
||||
layout (location = 7) in uint grid_width;
|
||||
|
||||
// The background or foreground color for the fragment, depending on
|
||||
// whether this is a background or foreground pass.
|
||||
flat out vec4 color;
|
||||
|
||||
// The x/y coordinate for the glyph representing the font.
|
||||
out vec2 glyph_tex_coords;
|
||||
|
||||
// The position of the cell top-left corner in screen cords. z and w
|
||||
// are width and height.
|
||||
flat out vec2 screen_cell_pos;
|
||||
|
||||
// Pass the mode forward to the fragment shader.
|
||||
flat out uint mode;
|
||||
|
||||
uniform sampler2D text;
|
||||
uniform sampler2D text_color;
|
||||
uniform vec2 cell_size;
|
||||
uniform mat4 projection;
|
||||
uniform float underline_position;
|
||||
uniform float underline_thickness;
|
||||
uniform float strikethrough_position;
|
||||
uniform float strikethrough_thickness;
|
||||
|
||||
/********************************************************************
|
||||
* Modes
|
||||
*
|
||||
*-------------------------------------------------------------------
|
||||
* MODE_BG
|
||||
*
|
||||
* In MODE_BG, this shader renders only the background color for the
|
||||
* cell. This is a simple mode where we generate a simple rectangle
|
||||
* made up of 4 vertices and then it is filled. In this mode, the output
|
||||
* "color" is the fill color for the bg.
|
||||
*
|
||||
*-------------------------------------------------------------------
|
||||
* MODE_FG
|
||||
*
|
||||
* In MODE_FG, the shader renders the glyph onto this cell and utilizes
|
||||
* the glyph texture "text". In this mode, the output "color" is the
|
||||
* fg color to use for the glyph.
|
||||
*
|
||||
*/
|
||||
|
||||
void main() {
|
||||
// We always forward our mode unmasked because the fragment
|
||||
// shader doesn't use any of the masks.
|
||||
mode = mode_in;
|
||||
|
||||
// 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;
|
||||
|
||||
// Our Z value. For now we just use grid_z directly but we pull it
|
||||
// out here so the variable name is more uniform to our cell_pos and
|
||||
// in case we want to do any other math later.
|
||||
float cell_z = 0.0;
|
||||
|
||||
// Turn the cell position into a vertex point depending on the
|
||||
// gl_VertexID. Since we use instanced drawing, we have 4 vertices
|
||||
// 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
|
||||
// or discard the value for the vertex.
|
||||
//
|
||||
// 0 = top-right
|
||||
// 1 = bot-right
|
||||
// 2 = bot-left
|
||||
// 3 = top-left
|
||||
vec2 position;
|
||||
position.x = (gl_VertexID == 0 || gl_VertexID == 1) ? 1. : 0.;
|
||||
position.y = (gl_VertexID == 0 || gl_VertexID == 3) ? 0. : 1.;
|
||||
|
||||
// Scaled for wide chars
|
||||
vec2 cell_size_scaled = cell_size;
|
||||
cell_size_scaled.x = cell_size_scaled.x * grid_width;
|
||||
|
||||
switch (mode) {
|
||||
case MODE_BG:
|
||||
// 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_scaled * position;
|
||||
|
||||
gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
|
||||
color = bg_color_in / 255.0;
|
||||
break;
|
||||
|
||||
case MODE_FG:
|
||||
case MODE_FG_COLOR:
|
||||
vec2 glyph_offset_calc = glyph_offset;
|
||||
|
||||
// If the glyph is larger than our cell, we need to downsample it.
|
||||
// The "+ 3" here is to give some wiggle room for fonts that are
|
||||
// BARELY over it.
|
||||
vec2 glyph_size_downsampled = glyph_size;
|
||||
if (glyph_size_downsampled.y > cell_size_scaled.y + 2) {
|
||||
// Magic 0.9 and 1.1 are padding to make emoji look better
|
||||
glyph_size_downsampled.y = cell_size_scaled.y * 0.9;
|
||||
glyph_size_downsampled.x = glyph_size.x * (glyph_size_downsampled.y / glyph_size.y);
|
||||
glyph_offset_calc.y = glyph_offset.y * 1.1 * (glyph_size_downsampled.y / glyph_size.y);
|
||||
}
|
||||
|
||||
// The glyph_offset.y is the y bearing, a y value that when added
|
||||
// to the baseline is the offset (+y is up). Our grid goes down.
|
||||
// So we flip it with `cell_size.y - glyph_offset.y`.
|
||||
glyph_offset_calc.y = cell_size_scaled.y - glyph_offset_calc.y;
|
||||
|
||||
// Calculate the final position of the cell.
|
||||
cell_pos = cell_pos + (glyph_size_downsampled * position) + glyph_offset_calc;
|
||||
gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
|
||||
|
||||
// We need to convert our texture position and size to normalized
|
||||
// device coordinates (0 to 1.0) by dividing by the size of the texture.
|
||||
ivec2 text_size;
|
||||
switch(mode) {
|
||||
case MODE_FG:
|
||||
text_size = textureSize(text, 0);
|
||||
break;
|
||||
|
||||
case MODE_FG_COLOR:
|
||||
text_size = textureSize(text_color, 0);
|
||||
break;
|
||||
}
|
||||
vec2 glyph_tex_pos = glyph_pos / text_size;
|
||||
vec2 glyph_tex_size = glyph_size / text_size;
|
||||
glyph_tex_coords = glyph_tex_pos + glyph_tex_size * position;
|
||||
|
||||
// Set our foreground color output
|
||||
color = fg_color_in / 255.;
|
||||
break;
|
||||
|
||||
case MODE_CURSOR_RECT:
|
||||
// Same as background since we're taking up the whole cell.
|
||||
cell_pos = cell_pos + cell_size_scaled * position;
|
||||
|
||||
gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
|
||||
color = bg_color_in / 255.0;
|
||||
break;
|
||||
|
||||
case MODE_CURSOR_RECT_HOLLOW:
|
||||
// Top-left position of this cell is needed for the hollow rect.
|
||||
screen_cell_pos = cell_pos;
|
||||
|
||||
// Same as background since we're taking up the whole cell.
|
||||
cell_pos = cell_pos + cell_size_scaled * position;
|
||||
|
||||
gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
|
||||
color = bg_color_in / 255.0;
|
||||
break;
|
||||
|
||||
case MODE_CURSOR_BAR:
|
||||
// Make the bar a smaller version of our cell
|
||||
vec2 bar_size = vec2(cell_size.x * 0.2, cell_size.y);
|
||||
|
||||
// Same as background since we're taking up the whole cell.
|
||||
cell_pos = cell_pos + bar_size * position;
|
||||
|
||||
gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
|
||||
color = bg_color_in / 255.0;
|
||||
break;
|
||||
|
||||
case MODE_UNDERLINE:
|
||||
// Underline Y value is just our thickness
|
||||
vec2 underline_size = vec2(cell_size_scaled.x, underline_thickness);
|
||||
|
||||
// Position the underline where we are told to
|
||||
vec2 underline_offset = vec2(cell_size_scaled.x, underline_position) ;
|
||||
|
||||
// Go to the bottom of the cell, take away the size of the
|
||||
// underline, and that is our position. We also float it slightly
|
||||
// above the bottom.
|
||||
cell_pos = cell_pos + underline_offset - (underline_size * position);
|
||||
|
||||
gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
|
||||
color = fg_color_in / 255.0;
|
||||
break;
|
||||
|
||||
case MODE_STRIKETHROUGH:
|
||||
// Strikethrough Y value is just our thickness
|
||||
vec2 strikethrough_size = vec2(cell_size_scaled.x, strikethrough_thickness);
|
||||
|
||||
// Position the strikethrough where we are told to
|
||||
vec2 strikethrough_offset = vec2(cell_size_scaled.x, strikethrough_position) ;
|
||||
|
||||
// Go to the bottom of the cell, take away the size of the
|
||||
// strikethrough, and that is our position. We also float it slightly
|
||||
// above the bottom.
|
||||
cell_pos = cell_pos + strikethrough_offset - (strikethrough_size * position);
|
||||
|
||||
gl_Position = projection * vec4(cell_pos, cell_z, 1.0);
|
||||
color = fg_color_in / 255.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user