-
-
Notifications
You must be signed in to change notification settings - Fork 561
Expand file tree
/
Copy pathcommon.hpp
More file actions
243 lines (216 loc) · 8.1 KB
/
Copy pathcommon.hpp
File metadata and controls
243 lines (216 loc) · 8.1 KB
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#pragma once
namespace mbgl {
namespace shaders {
constexpr auto prelude = R"(
#include <metal_stdlib>
using namespace metal;
// The maximum allowed miter limit is 2.0 at the moment. the extrude normal is stored
// in a byte (-128..127). We scale regular normals up to length 63, but there are also
// "special" normals that have a bigger length (of up to 126 in this case).
#define LINE_NORMAL_SCALE (1.0 / (127 / 2))
// The attribute conveying progress along a line is scaled to [0, 2^15).
#define MAX_LINE_DISTANCE 32767.0
#define SDF_PX 8.0
// OpenGL `mod` is `x-y*floor(x/y)` where `floor` rounds down.
// Metal `fmod` is `x-y*trunc(x/y)` where `trunc` rounds toward zero.
// This function provides GL-compatible modulus for porting GLSL shaders.
template <typename T1, typename T2>
inline auto glMod(T1 x, T2 y) { return x - y * metal::floor(x/y); }
inline float radians(float degrees) {
return M_PI_F * degrees / 180.0;
}
// Unpack a pair of values that have been packed into a single float.
// The packed values are assumed to be 8-bit unsigned integers, and are
// packed like so: packedValue = floor(input[0]) * 256 + input[1],
float2 unpack_float(const float packedValue) {
const int packedIntValue = int(packedValue);
const int v0 = packedIntValue / 256;
return float2(v0, packedIntValue - v0 * 256);
}
float2 unpack_opacity(const float packedOpacity) {
return float2(float(int(packedOpacity) / 2) / 127.0, glMod(packedOpacity, 2.0));
}
// To minimize the number of attributes needed, we encode a 4-component
// color into a pair of floats (i.e. a vec2) as follows:
// [ floor(color.r * 255) * 256 + color.g * 255, floor(color.b * 255) * 256 + color.g * 255 ]
float4 decode_color(const float2 encoded) {
return float4(unpack_float(encoded[0]) / 255, unpack_float(encoded[1]) / 255);
}
// Unpack a pair of paint values and interpolate between them.
float unpack_mix_float(device const float packedValue[2], const float t) {
return mix(packedValue[0], packedValue[1], t == 0 ? 1 : t);
}
float unpack_mix_float(const float2 packedValue, const float t) {
return mix(packedValue[0], packedValue[1], t);
}
// Unpack a pair of paint values and interpolate between them.
float4 unpack_mix_color(device const float packedColors[4], const float t) {
return mix(decode_color(float2(packedColors[0], packedColors[1])),
decode_color(float2(packedColors[2], packedColors[3])), t == 0 ? 1 : t);
}
float4 unpack_mix_color(const float4 packedColors, const float t) {
return mix(decode_color(float2(packedColors[0], packedColors[1])),
decode_color(float2(packedColors[2], packedColors[3])), t);
}
// Unpack pattern position
inline float2 get_pattern_pos(const float2 pixel_coord_upper, const float2 pixel_coord_lower,
const float2 pattern_size, const float tile_units_to_pixels, const float2 pos) {
const float2 offset = glMod(glMod(glMod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
return (tile_units_to_pixels * pos + offset) / pattern_size;
}
template<class ForwardIt, class T>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, thread const T& value)
{
size_t count = last - first;
while (count > 0)
{
ForwardIt it = first;
const size_t step = count / 2;
it += step;
if (!(value < *it))
{
first = ++it;
count -= step + 1;
}
else {
count = step;
}
}
return first;
}
float interpolationFactor(float base, float rangeMin, float rangeMax, float z) {
const float zoomDiff = rangeMax - rangeMin;
const float zoomProgress = z - rangeMin;
if (zoomDiff == 0) {
return 0;
} else if (base == 1.0f) {
return zoomProgress / zoomDiff;
} else {
return (pow(base, zoomProgress) - 1) / (pow(base, zoomDiff) - 1);
}
}
enum class GPUInterpType : uint16_t {
Step,
Linear,
Exponential,
Bezier
};
enum class GPUOutputType : uint16_t {
Float,
Color,
};
enum class GPUOptions : uint16_t {
None = 0,
IntegerZoom = 1 << 0,
Transitioning = 1 << 1,
};
bool operator&(GPUOptions a, GPUOptions b) { return (uint16_t)a & (uint16_t)b; }
constant const int maxExprStops = 16;
struct alignas(16) GPUExpression {
GPUOutputType outputType;
uint16_t stopCount;
GPUOptions options;
GPUInterpType interpolation;
union InterpOptions {
struct Exponential {
float base;
} exponential;
struct Bezier {
float x1;
float y1;
float x2;
float y2;
} bezier;
} interpOptions;
float inputs[maxExprStops];
union Stops {
float floats[maxExprStops];
float2 colors[maxExprStops];
} stops;
float eval(float zoom) device const {
const auto effectiveZoom = (options & GPUOptions::IntegerZoom) ? floor(zoom) : zoom;
const auto index = find(effectiveZoom);
if (index == 0) {
return stops.floats[0];
} else if (index == stopCount) {
return stops.floats[stopCount - 1];
}
switch (interpolation) {
case GPUInterpType::Step: return stops.floats[index - 1];
default: assert(false);
[[fallthrough]];
case GPUInterpType::Linear: assert(interpOptions.exponential.base == 1.0f);
[[fallthrough]];
case GPUInterpType::Exponential: {
const float rangeBeg = inputs[index - 1];
const float rangeEnd = inputs[index];
const auto t = interpolationFactor(interpOptions.exponential.base, rangeBeg, rangeEnd, effectiveZoom);
return mix(stops.floats[index - 1], stops.floats[index], t);
}
case GPUInterpType::Bezier:
assert(false);
return stops.floats[0];
}
}
float4 evalColor(float zoom) device const {
const auto effectiveZoom = (options & GPUOptions::IntegerZoom) ? floor(zoom) : zoom;
const auto index = find(effectiveZoom);
if (index == 0) {
return getColor(0);
} else if (index == stopCount) {
return getColor(stopCount - 1);
}
switch (interpolation) {
case GPUInterpType::Step:
return getColor(index - 1);
default:
assert(false);
[[fallthrough]];
case GPUInterpType::Linear:
assert(interpOptions.exponential.base == 1.0f);
[[fallthrough]];
case GPUInterpType::Exponential: {
const float rangeBeg = inputs[index - 1];
const float rangeEnd = inputs[index];
const auto t = interpolationFactor(interpOptions.exponential.base, rangeBeg, rangeEnd, effectiveZoom);
return mix(getColor(index - 1), getColor(index), clamp(t, 0.0, 1.0));
}
case GPUInterpType::Bezier:
assert(false);
return getColor(0);
}
}
/// Get the index of the entry to use from the zoom level
size_t find(float zoom) device const {
return upper_bound(&inputs[0], &inputs[stopCount], zoom) - &inputs[0];
}
float4 getColor(size_t index) device const { return decode_color(stops.colors[index]); }
};
static_assert(sizeof(GPUExpression) == 32 + (4 + 8) * maxExprStops, "wrong size");
static_assert(sizeof(GPUExpression) % 16 == 0, "wrong alignment");
struct alignas(16) GlobalPaintParamsUBO {
/* 0 */ float2 pattern_atlas_texsize;
/* 8 */ float2 units_to_pixels;
/* 16 */ float2 world_size;
/* 24 */ float camera_to_center_distance;
/* 28 */ float symbol_fade_change;
/* 32 */ float aspect_ratio;
/* 36 */ float pixel_ratio;
/* 40 */ float map_zoom;
/* 44 */ float pad1;
/* 48 */
};
static_assert(sizeof(GlobalPaintParamsUBO) == 3 * 16, "wrong size");
enum {
idGlobalPaintParamsUBO,
idGlobalUBOIndex,
globalUBOCount,
};
enum {
idDrawableReservedVertexOnlyUBO = globalUBOCount,
idDrawableReservedFragmentOnlyUBO,
drawableReservedUBOCount
};
)";
}
} // namespace mbgl