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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
#version 330 core
layout (location = 0) in vec3 in_quad;
layout (std140) uniform Matrices {
mat4 proj;
mat4 view;
};
// world chunk position
const int CHUNK_SIZE = 16;
uniform ivec3 chunk_position;
const int MAX_FACES = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
layout (std140) uniform Face {
// normaly a uint but std140 layout
// requires 16-byte alignment
uvec4 face_data[MAX_FACES / 4];
};
flat out uvec2 pass_data;
out float pass_ao;
const mat3 ROT90 = mat3(
0.0, 0.0, 1.0,
0.0, 1.0, 0.0,
-1.0, 0.0, 0.0
);
uint get_half(int index)
{
int arr_index = index / 4;
int vec_index = index % 4;
return face_data[arr_index][vec_index];
}
uvec2 get_data(int index)
{
uint lower = get_half(index * 2);
uint upper = get_half(index * 2 + 1);
return uvec2(lower, upper);
}
bool get_ao_rotate(uint data)
{
vec4 ao;
ao.x = (data >> 0) & 3u;
ao.y = (data >> 2) & 3u;
ao.z = (data >> 4) & 3u;
ao.w = (data >> 6) & 3u;
float a = abs(ao.x - ao.w);
float b = abs(ao.y - ao.z);
return a > b;
}
float get_ao(uint data, uint face)
{
vec4 ao;
ao.x = (data >> 0) & 3u;
ao.y = (data >> 2) & 3u;
ao.z = (data >> 4) & 3u;
ao.w = (data >> 6) & 3u;
switch (face) {
case 0u: // PX
case 2u: // PY
case 4u: // PZ
ao = ao.xywz;
if (get_ao_rotate(data))
ao = ao.wxyz;
break;
case 1u: // NX
case 3u: // NY
case 5u: // NZ
if (get_ao_rotate(data))
ao = ao.ywxz;
ao = ao.wzxy;
break;
}
return ao[gl_VertexID];
}
vec3 rotate(vec3 v, uint face)
{
switch(face) {
case 0u: // PX
case 1u: // NX
v = vec3(v.x, v.z, -v.y + 1);
break;
case 2u: // PY
case 3u: // NY
v = vec3(-v.z + 1, v.y, v.x);
break;
case 4u: // PZ
case 5u: // NZ
v = vec3(v.y, -v.x + 1, v.z);
break;
}
return v;
}
vec3 get_quad(uint face, uint width, uint height)
{
vec3 quad = in_quad;
quad.x *= width;
quad.y *= height;
switch(face) {
case 0u: // PX
quad = quad.yzx + vec3(1, 0, 0);
break;
case 1u: // NX
quad = quad.yxz;
break;
case 2u: // PY
quad = quad.xyz + vec3(0, 1, 0);
break;
case 3u: // NY
quad = quad.zyx;
break;
case 4u: // PZ
quad = quad.zxy + vec3(0, 0, 1);
break;
case 5u: // NZ
quad = quad.xzy;
break;
}
return quad;
}
void main(void)
{
// get face data
uvec2 data = get_data(gl_InstanceID);
uint x = (data.x >> 0) & 31u;
uint y = (data.x >> 5) & 31u;
uint z = (data.x >> 10) & 31u;
uint width = (data.x >> 15) & 31u;
uint height = (data.x >> 20) & 31u;
uint face = (data.x >> 25) & 7u;
// get quad verts
vec3 quad = get_quad(face, width, height);
if (get_ao_rotate(data.y))
quad = rotate(quad, face);
// get position
vec3 position = vec3(x, y, z);
position += chunk_position * CHUNK_SIZE;
position += quad;
// draw
gl_Position = proj * view * vec4(position, 1.0);
// fragment input
pass_data = data;
pass_ao = get_ao(data.y, face);
}
|