mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 22:28:24 +02:00
Move clipping of graphics into the shader using gl_ClipDistance
This simplifies our code and also fixes the image distortion when partially off screen reported in #6467
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
out vec2 texcoord;
|
||||
uniform vec4 src_rect, dest_rect;
|
||||
out float gl_ClipDistance[4];
|
||||
uniform vec4 src_rect, dest_rect, viewport;
|
||||
|
||||
#define left 0
|
||||
#define top 1
|
||||
@@ -17,4 +18,8 @@ void main() {
|
||||
ivec2 pos = vertex_pos_map[gl_VertexID];
|
||||
texcoord = vec2(src_rect[pos.x], src_rect[pos.y]);
|
||||
gl_Position = vec4(dest_rect[pos.x], dest_rect[pos.y], 0, 1);
|
||||
gl_ClipDistance[left] = gl_Position.x - viewport[left];
|
||||
gl_ClipDistance[right] = viewport[right] - gl_Position.x;
|
||||
gl_ClipDistance[top] = viewport[top] - gl_Position.y;
|
||||
gl_ClipDistance[bottom] = gl_Position.y - viewport[bottom];
|
||||
}
|
||||
|
||||
@@ -469,49 +469,23 @@ draw_background_image(OSWindow *w) {
|
||||
unbind_program();
|
||||
}
|
||||
|
||||
static void
|
||||
fit_image_in_viewport(GraphicsUniforms *u, ImageRenderData *rd, ImageRect viewport) {
|
||||
// dest_rect: x: -1 to 1, y: 1 to -1. src_rect: x: 0 to 1 for both axes
|
||||
ImageRect src_rect = rd->src_rect, dest_rect = rd->dest_rect;
|
||||
const float img_width = dest_rect.right - dest_rect.left;
|
||||
if (viewport.left > dest_rect.left) {
|
||||
float frac = 1.f - (dest_rect.right - viewport.left) / img_width;
|
||||
dest_rect.left = viewport.left;
|
||||
src_rect.left += frac; // src_rect: left is 0 right is 1
|
||||
}
|
||||
if (viewport.right < dest_rect.right) {
|
||||
float frac = 1.f - (viewport.right - dest_rect.left) / img_width;
|
||||
dest_rect.right = viewport.right;
|
||||
src_rect.right -= frac; // src_rect: left is 0 right is 1
|
||||
}
|
||||
const float img_height = dest_rect.top - dest_rect.bottom;
|
||||
if (viewport.top < dest_rect.top) {
|
||||
float frac = 1.f - (viewport.top - dest_rect.bottom) / img_height;
|
||||
dest_rect.top = viewport.top;
|
||||
src_rect.top += frac; // src_rect.bottom is 1 top is 0
|
||||
}
|
||||
if (viewport.bottom > dest_rect.bottom) {
|
||||
float frac = 1.f - (dest_rect.top - viewport.bottom) / img_height;
|
||||
dest_rect.bottom = viewport.bottom;
|
||||
src_rect.bottom -= frac; // src_rect.bottom is 1 top is 0
|
||||
}
|
||||
glUniform4f(u->src_rect, src_rect.left, src_rect.top, src_rect.right, src_rect.bottom);
|
||||
glUniform4f(u->dest_rect, dest_rect.left, dest_rect.top, dest_rect.right, dest_rect.bottom);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_graphics(int program, ssize_t vao_idx, ImageRenderData *data, GLuint start, GLuint count, ImageRect viewport) {
|
||||
bind_program(program);
|
||||
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
|
||||
GraphicsUniforms *u = &graphics_program_layouts[program].uniforms;
|
||||
glUniform4f(u->viewport, viewport.left, viewport.top, viewport.right, viewport.bottom);
|
||||
glEnable(GL_CLIP_DISTANCE0); glEnable(GL_CLIP_DISTANCE1); glEnable(GL_CLIP_DISTANCE2); glEnable(GL_CLIP_DISTANCE3);
|
||||
for (GLuint i=0; i < count;) {
|
||||
ImageRenderData *rd = data + start + i;
|
||||
glBindTexture(GL_TEXTURE_2D, rd->texture_id);
|
||||
for (GLuint k=0; k < rd->group_count; k++, i++) {
|
||||
fit_image_in_viewport(u, rd, viewport);
|
||||
glUniform4f(u->src_rect, rd->src_rect.left, rd->src_rect.top, rd->src_rect.right, rd->src_rect.bottom);
|
||||
glUniform4f(u->dest_rect, rd->dest_rect.left, rd->dest_rect.top, rd->dest_rect.right, rd->dest_rect.bottom);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
}
|
||||
}
|
||||
glDisable(GL_CLIP_DISTANCE0); glDisable(GL_CLIP_DISTANCE1); glDisable(GL_CLIP_DISTANCE2); glDisable(GL_CLIP_DISTANCE3);
|
||||
bind_vertex_array(vao_idx);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user