~rycwo/forge

forge/shader/gui_rect.vert.glsl -rw-r--r-- 2.7 KiB
d7ee94d6Ryan Chan Fix missing cd in .build.yml 2 months ago
                                                                                
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
// This file is part of Forge, the foundation library for Forge tools.
//
// Copyright (C) 2021 Ryan Chan <rycwo@posteo.net>
// SPDX-License-Identifier: GPL-3.0-only
//
// This Source Code Form is subject to the terms of the GNU General Public
// License v3.0 only. You should have received a copy of the license along with
// this program. If not, see <https://www.gnu.org/licenses/>.

#version 460 core

// See struct gui_rect in forge/gui_type.h
struct primitive {
	vec4 rect;
	uint color;
	uint border_color;
	uint border;
	uint flags;
};

layout(std140, binding = 0) uniform context {
	mat4 projection;
	vec2 viewport;
};

layout(std430, binding = 0) restrict readonly buffer clip_buffer {
	vec4 clips[];
};

layout(std430, binding = 1) restrict readonly buffer prim_buffer {
	primitive prims[];
};

layout(location = 0) out vertex_attr {
	flat vec4 color;
	flat vec4 border_color;
	flat vec2 size;
	flat vec2 center;
	flat float border_width;
	flat float corner_radius;
	flat int circle;
} vert_out;

const int clip_mask = 0xFFFFFF;
const vec2 quad[6] = vec2[6](
	vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0),
	vec2(1.0, 1.0), vec2(0.0, 0.0), vec2(0.0, 1.0)
);

void
main(void) {
	// Vertices of the triangle strip used to build the quad are defined
	// in CCW order. We expect the vertices to be output in the order:
	// v0, v1, v2 for t1, then v2, v1, v3 for t2.
	//
	// v2 ┌─────┐ v3
	//    │ ╲ t2│
	//    │  ╲  │
	//    │t1 ╲ │
	// v0 └─────┘ v1

	primitive prim = prims[gl_VertexID / 6];

	vec2 v2 = prim.rect.xy;
	vec2 v1 = prim.rect.zw + v2;

	vec4 color = unpackUnorm4x8(prim.color);
	vec4 border_color = unpackUnorm4x8(prim.border_color);

	vec2 border = unpackHalf2x16(prim.border);
	float border_width = border[0];
	float corner_radius = border[1];

	uint clip_index = prim.flags & clip_mask;
	uint shape = (prim.flags & (~clip_mask)) >> 24;

	// Compute size without border and extensions
	vec2 size = v1 - v2;

	vec2 center = (projection * vec4(v2 + size * 0.5, 0.0, 1.0)).xy;

	// Rect is expanded by an additional pixel to accomodate for anti-aliasing
	v2 -= vec2(border_width + 1.0);
	v1 += vec2(border_width + 1.0);

	// Bear in mind the Y-axis is flipped in the window-space to NDC
	// transformation when we multiply the position by the projection matrix.
	vec2 position = mix(v1, v2, quad[gl_VertexID % 6]);

	// Apply clip rect
	vec4 clip = clips[clip_index];
	position = clamp(position, clip.xy, clip.xy + clip.zw);

	gl_Position = projection * vec4(position, 0.0, 1.0);

	vert_out.color = color;
	vert_out.border_color = border_color;
	vert_out.border_width = border_width;
	vert_out.corner_radius = corner_radius;
	vert_out.size = size;
	vert_out.center = (center * 0.5 + 0.5) * viewport;
	vert_out.circle = int(shape);
}