Blender V5.0
subpatch.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "util/hash.h"
8#include "util/math_float2.h"
9
11
12class Patch;
13
14enum {
18};
19
20/* SubEdge */
21
22struct SubEdge {
27
28 /* Vertex indices. */
31
32 /* If edge was split, vertex index in the middle. */
34
35 /* Number of segments the edge will be diced into, see DiagSplit paper. */
36 int T = 0;
37
38 /* Estimated length of edge, for determining preferred split direction. */
39 float length = 0.0f;
40
41 /* Index of the second vert from this edges corner along the edge towards the next corner. */
43
44 /* How many times an edge was subdivided to get this edge. */
45 int depth = 0;
46
47 SubEdge() = default;
48
49 int get_vert_along_edge(const int n) const
50 {
51 assert(n >= 0 && n <= T);
52
53 if (n == 0) {
54 return start_vert_index;
55 }
56 if (n == T) {
57 return end_vert_index;
58 }
59
60 return second_vert_index + n - 1;
61 }
62
63 bool must_split() const
64 {
65 return T == DSPLIT_NON_UNIFORM;
66 }
67
68 struct Hash {
69 size_t operator()(const SubEdge &edge) const
70 {
71 int a = edge.start_vert_index;
72 int b = edge.end_vert_index;
73 if (b > a) {
74 std::swap(a, b);
75 }
76 return hash_uint2(a, b);
77 }
78 };
79
80 struct Equal {
81 size_t operator()(const SubEdge &a, const SubEdge &b) const
82 {
83 return (a.start_vert_index == b.start_vert_index && a.end_vert_index == b.end_vert_index) ||
84 (a.start_vert_index == b.end_vert_index && a.end_vert_index == b.start_vert_index);
85 }
86 };
87};
88
89/* SubPatch */
90
91class SubPatch {
92 public:
93 /* Patch this is a subpatch of. */
94 const Patch *patch = nullptr;
95 /* Face and corner. */
96 int face_index = 0;
97 int corner = 0;
98 /* Is a triangular patch instead of a quad patch? */
99 enum { TRIANGLE, QUAD } shape = QUAD;
100 /* Vertex indices for inner grid start at this index. */
102 /* Triangle indices. */
104
105 /* Edge of patch. */
106 struct Edge {
108
109 /* Is the direction of this edge reverse compared to SubEdge? */
111
112 /* Is this subpatch responsible for owning attributes for the start vertex? */
114 /* Is this subpatch responsible for owning attributes for edge vertices? */
116
117 /* Get vertex indices in the direction of this patch edge, will take into
118 * account the reversed flag to flip the indices. */
120 {
121 return (reversed) ? edge->end_vert_index : edge->start_vert_index;
122 }
123 int mid_vert_index() const
124 {
125 return edge->mid_vert_index;
126 }
127 int end_vert_index() const
128 {
129 return (reversed) ? edge->start_vert_index : edge->end_vert_index;
130 }
131
132 int get_vert_along_edge(const int n_relative) const
133 {
134 assert(n_relative >= 0 && n_relative <= edge->T);
135
136 const int n = (reversed) ? edge->T - n_relative : n_relative;
137
138 return edge->get_vert_along_edge(n);
139 }
140 };
141
142 /*
143 * edge2
144 * uv3 ←------------ uv2
145 * | ↑
146 * edge3 | | edge1
147 * ↓ |
148 * uv0 ------------→ uv1
149 * edge0
150 *
151 * uv2
152 * | \
153 * | \
154 * edge2 | \ edge1
155 * | \
156 * ↓ \
157 * uv0 --→ uv1
158 * edge0
159 */
160
161 /* UV within patch, counter-clockwise starting from uv (0, 0) towards (1, 0) etc. */
162 float2 uvs[4] = {zero_float2(), make_float2(1.0f, 0.0f), one_float2(), make_float2(0.0f, 1.0f)};
163
164 /* Edges of this subpatch. */
165 Edge edges[4] = {};
166
167 explicit SubPatch(const Patch *patch, const int face_index, const int corner = 0)
169 {
170 }
171
173 {
174 if (shape == TRIANGLE) {
175 const int M = max(max(edges[0].edge->T, edges[1].edge->T), edges[2].edge->T);
176 if (M <= 2) {
177 /* No inner grid. */
178 return 0;
179 }
180 /* 1 + 2 + .. + M-1 */
181 return M * (M - 1) / 2;
182 }
183
184 const int Mu = max(edges[0].edge->T, edges[2].edge->T);
185 const int Mv = max(edges[3].edge->T, edges[1].edge->T);
186 return (Mu - 1) * (Mv - 1);
187 }
188
190 {
191 if (shape == TRIANGLE) {
192 const int M = max(max(edges[0].edge->T, edges[1].edge->T), edges[2].edge->T);
193 if (M == 1) {
194 return 1;
195 }
196 if (M == 2) {
197 return edges[0].edge->T + edges[1].edge->T + edges[2].edge->T - 2;
198 }
199
200 const int inner_M = M - 2;
201 const int inner_triangles = inner_M * inner_M;
202 const int edge_triangles = edges[0].edge->T + edges[1].edge->T + edges[2].edge->T +
203 inner_M * 3;
204 return inner_triangles + edge_triangles;
205 }
206
207 const int Mu = max(edges[0].edge->T, edges[2].edge->T);
208 const int Mv = max(edges[3].edge->T, edges[1].edge->T);
209
210 if (Mu == 1) {
211 return edges[3].edge->T + edges[1].edge->T;
212 }
213 if (Mv == 1) {
214 return edges[0].edge->T + edges[2].edge->T;
215 }
216
217 const int inner_triangles = (Mu - 2) * (Mv - 2) * 2;
218 const int edge_triangles = edges[0].edge->T + edges[2].edge->T + edges[3].edge->T +
219 edges[1].edge->T + ((Mu - 2) * 2) + ((Mv - 2) * 2);
220
221 return inner_triangles + edge_triangles;
222 }
223
224 int get_vert_along_edge(const int edge, const int n) const
225 {
226 return edges[edge].get_vert_along_edge(n);
227 }
228
229 int get_vert_along_edge_reverse(const int edge, const int n) const
230 {
231 return get_vert_along_edge(edge, edges[edge].edge->T - n);
232 }
233
234 int get_inner_grid_vert_triangle(int i, int j) const
235 {
236 /* Rows `(1 + 2 + .. + j)`, and column `i`. */
237 const int offset = j * (j + 1) / 2 + i;
238 assert(offset < calc_num_inner_verts());
239 return inner_grid_vert_offset + offset;
240 }
241
242 int get_vert_along_grid_edge(const int edge, const int n) const
243 {
244 if (shape == TRIANGLE) {
245 const int M = max(max(edges[0].edge->T, edges[1].edge->T), edges[2].edge->T);
246 const int inner_M = M - 2;
247 assert(M >= 2);
248
249 switch (edge) {
250 case 0: {
251 return get_inner_grid_vert_triangle(n, n);
252 }
253 case 1: {
254 return get_inner_grid_vert_triangle(inner_M - n, inner_M);
255 }
256 case 2: {
257 return get_inner_grid_vert_triangle(0, inner_M - n);
258 }
259 default:
260 assert(0);
261 break;
262 }
263
264 return -1;
265 }
266
267 const int Mu = max(edges[0].edge->T, edges[2].edge->T);
268 const int Mv = max(edges[3].edge->T, edges[1].edge->T);
269
270 assert(Mu >= 2 && Mv >= 2);
271
272 switch (edge) {
273 case 0: {
274 return inner_grid_vert_offset + n;
275 }
276 case 1: {
277 return inner_grid_vert_offset + (Mu - 2) + n * (Mu - 1);
278 }
279 case 2: {
280 const int reverse_n = (Mu - 2) - n;
281 return inner_grid_vert_offset + (Mu - 1) * (Mv - 2) + reverse_n;
282 }
283 case 3: {
284 const int reverse_n = (Mv - 2) - n;
285 return inner_grid_vert_offset + reverse_n * (Mu - 1);
286 }
287 default:
288 assert(0);
289 break;
290 }
291
292 return -1;
293 }
294
296 {
297 /* Map UV from subpatch to patch parametric coordinates. */
298 if (shape == TRIANGLE) {
299 return clamp((1.0f - uv.x - uv.y) * uvs[0] + uv.x * uvs[1] + uv.y * uvs[2],
300 zero_float2(),
301 one_float2());
302 }
303
304 const float2 d0 = interp(uvs[0], uvs[3], uv.y);
305 const float2 d1 = interp(uvs[1], uvs[2], uv.y);
306 return clamp(interp(d0, d1, uv.x), zero_float2(), one_float2());
307 }
308};
309
Definition patch.h:12
int get_inner_grid_vert_triangle(int i, int j) const
Definition subpatch.h:234
enum SubPatch::@271217051357320143155373165321151177022113114126 shape
int get_vert_along_edge_reverse(const int edge, const int n) const
Definition subpatch.h:229
int get_vert_along_edge(const int edge, const int n) const
Definition subpatch.h:224
float2 uvs[4]
Definition subpatch.h:162
int inner_grid_vert_offset
Definition subpatch.h:101
@ TRIANGLE
Definition subpatch.h:99
int calc_num_triangles() const
Definition subpatch.h:189
const Patch * patch
Definition subpatch.h:94
int face_index
Definition subpatch.h:96
SubPatch(const Patch *patch, const int face_index, const int corner=0)
Definition subpatch.h:167
int get_vert_along_grid_edge(const int edge, const int n) const
Definition subpatch.h:242
Edge edges[4]
Definition subpatch.h:165
int calc_num_inner_verts() const
Definition subpatch.h:172
float2 map_uv(float2 uv) const
Definition subpatch.h:295
int corner
Definition subpatch.h:97
int triangles_offset
Definition subpatch.h:103
#define CCL_NAMESPACE_END
#define assert(assertion)
constexpr T clamp(T, U, U) RET
ccl_device_inline uint hash_uint2(const uint kx, const uint ky)
Definition hash.h:139
ccl_device_inline float interp(const float a, const float b, const float t)
Definition math_base.h:502
ccl_device_inline float2 one_float2()
Definition math_float2.h:18
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
Definition math_float2.h:13
#define M
#define T
#define make_float2
size_t operator()(const SubEdge &a, const SubEdge &b) const
Definition subpatch.h:81
size_t operator()(const SubEdge &edge) const
Definition subpatch.h:69
int mid_vert_index
Definition subpatch.h:33
int get_vert_along_edge(const int n) const
Definition subpatch.h:49
SubEdge()=default
int second_vert_index
Definition subpatch.h:42
int start_vert_index
Definition subpatch.h:29
int end_vert_index
Definition subpatch.h:30
SubEdge(const int start_vert_index, const int end_vert_index, const int depth)
Definition subpatch.h:23
float length
Definition subpatch.h:39
bool must_split() const
Definition subpatch.h:63
int depth
Definition subpatch.h:45
int T
Definition subpatch.h:36
int start_vert_index() const
Definition subpatch.h:119
SubEdge * edge
Definition subpatch.h:107
int mid_vert_index() const
Definition subpatch.h:123
int end_vert_index() const
Definition subpatch.h:127
int get_vert_along_edge(const int n_relative) const
Definition subpatch.h:132
float x
float y
@ DSPLIT_MAX_DEPTH
Definition subpatch.h:16
@ DSPLIT_NON_UNIFORM
Definition subpatch.h:15
@ DSPLIT_MAX_SEGMENTS
Definition subpatch.h:17
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251