Blender V5.0
draw_curves_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "DNA_curves_types.h"
6
7#include "BKE_curves.hh"
8
9#include "GPU_batch.hh"
10#include "GPU_shader.hh"
11
13#include "draw_manager.hh"
14#include "draw_pass.hh"
15#include "draw_testing.hh"
16
17#include "draw_shader_shared.hh"
18
19namespace blender::draw {
20
22{
23 Manager manager;
24
25 gpu::Shader *sh = GPU_shader_create_from_info_name("draw_curves_test");
26
27 struct Indirection {
28 int index;
29 GPU_VERTEX_FORMAT_FUNC(Indirection, index);
30 };
31 gpu::VertBuf *indirection_ribbon_buf = GPU_vertbuf_create_with_format_ex(
32 Indirection::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
33 indirection_ribbon_buf->allocate(9);
34 indirection_ribbon_buf->data<int>().copy_from({0, -1, -2, -3, -4, 0x7FFFFFFF, 1, -1, -2});
35 gpu::Batch *batch_ribbon = GPU_batch_create_procedural(GPU_PRIM_TRI_STRIP, 2 * 9);
36
37 gpu::VertBuf *indirection_cylinder_buf = GPU_vertbuf_create_with_format_ex(
38 Indirection::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
39 indirection_cylinder_buf->allocate(6);
40 indirection_cylinder_buf->data<int>().copy_from({0, -1, -2, -3, 1, -1});
41 gpu::Batch *batch_cylinder = GPU_batch_create_procedural(GPU_PRIM_TRI_STRIP, (3 * 2 + 1) * 6);
42
43 struct PositionRadius {
44 float4 pos_rad;
45 GPU_VERTEX_FORMAT_FUNC(PositionRadius, pos_rad);
46 };
48 PositionRadius::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
49 pos_rad_buf->allocate(8);
50 pos_rad_buf->data<float4>().copy_from({float4{1.0f},
51 float4{0.75f},
52 float4{0.5f},
53 float4{0.25f},
54 float4{0.0f},
55 float4{0.0f},
56 float4{1.0f},
57 float4{2.0f}});
58
59 UniformBuffer<CurvesInfos> curves_info_buf;
60 curves_info_buf.is_point_attribute[0].x = 0;
61 curves_info_buf.is_point_attribute[1].x = 1;
62 /* Ribbon. */
63 curves_info_buf.vertex_per_segment = 2;
64 curves_info_buf.half_cylinder_face_count = 1;
65 curves_info_buf.push_update();
66
68 fb.ensure(int2(1, 1));
69
70 {
73 result_pos.clear_to_zero();
74 result_idx.clear_to_zero();
75
76 PassSimple pass("Ribbon Curves");
77 pass.init();
78 pass.framebuffer_set(&fb);
79 pass.shader_set(sh);
80 pass.bind_ubo("drw_curves", curves_info_buf);
81 pass.bind_texture("curves_pos_rad_buf", pos_rad_buf);
82 pass.bind_texture("curves_indirection_buf", indirection_ribbon_buf);
83 pass.bind_ssbo("result_pos_buf", result_pos);
84 pass.bind_ssbo("result_indices_buf", result_idx);
85 pass.draw(batch_ribbon);
87
88 manager.submit(pass);
89
90 /* Note: Expected values follows diagram shown in #142969. */
91
92 result_pos.read();
93 EXPECT_EQ(result_pos[0], 1.0f);
94 EXPECT_EQ(result_pos[1], 1.0f);
95 EXPECT_EQ(result_pos[2], 0.75f);
96 EXPECT_EQ(result_pos[3], 0.75f);
97 EXPECT_EQ(result_pos[4], 0.5f);
98 EXPECT_EQ(result_pos[5], 0.5f);
99 EXPECT_EQ(result_pos[6], 0.25f);
100 EXPECT_EQ(result_pos[7], 0.25f);
101 EXPECT_EQ(result_pos[8], 0.0f);
102 EXPECT_EQ(result_pos[9], 0.0f);
103 EXPECT_TRUE(isnan(result_pos[10]));
104 EXPECT_TRUE(isnan(result_pos[11]));
105 EXPECT_EQ(result_pos[12], 0.0f);
106 EXPECT_EQ(result_pos[13], 0.0f);
107 EXPECT_EQ(result_pos[14], 1.0f);
108 EXPECT_EQ(result_pos[15], 1.0f);
109 EXPECT_EQ(result_pos[16], 2.0f);
110 EXPECT_EQ(result_pos[17], 2.0f);
111
112 result_idx.read();
113 /* x: point_id, y: curve_id, z: curve_segment, w: azimuthal_offset */
114 EXPECT_EQ(result_idx[0], int4(0, 0, 0, -1));
115 EXPECT_EQ(result_idx[1], int4(0, 0, 0, 1));
116 EXPECT_EQ(result_idx[2], int4(1, 0, 1, -1));
117 EXPECT_EQ(result_idx[3], int4(1, 0, 1, 1));
118 EXPECT_EQ(result_idx[4], int4(2, 0, 2, -1));
119 EXPECT_EQ(result_idx[5], int4(2, 0, 2, 1));
120 EXPECT_EQ(result_idx[6], int4(3, 0, 3, -1));
121 EXPECT_EQ(result_idx[7], int4(3, 0, 3, 1));
122 EXPECT_EQ(result_idx[8], int4(4, 0, 4, -1));
123 EXPECT_EQ(result_idx[9], int4(4, 0, 4, 1));
124 EXPECT_EQ(result_idx[10], int4(5, 0, 0, -1)); /* End Of Curve */
125 EXPECT_EQ(result_idx[11], int4(5, 0, 0, 1)); /* End Of Curve */
126 EXPECT_EQ(result_idx[12], int4(5, 1, 0, -1));
127 EXPECT_EQ(result_idx[13], int4(5, 1, 0, 1));
128 EXPECT_EQ(result_idx[14], int4(6, 1, 1, -1));
129 EXPECT_EQ(result_idx[15], int4(6, 1, 1, 1));
130 EXPECT_EQ(result_idx[16], int4(7, 1, 2, -1));
131 EXPECT_EQ(result_idx[17], int4(7, 1, 2, 1));
132 }
133
134 /* Cylinder. */
135 curves_info_buf.vertex_per_segment = 7;
136 curves_info_buf.half_cylinder_face_count = 2;
137 curves_info_buf.push_update();
138
139 {
142 result_pos.clear_to_zero();
143 result_idx.clear_to_zero();
144
145 PassSimple pass("Cylinder Curves");
146 pass.init();
147 pass.framebuffer_set(&fb);
148 pass.shader_set(sh);
149 pass.bind_ubo("drw_curves", curves_info_buf);
150 pass.bind_texture("curves_pos_rad_buf", pos_rad_buf);
151 pass.bind_texture("curves_indirection_buf", indirection_cylinder_buf);
152 pass.bind_ssbo("result_pos_buf", result_pos);
153 pass.bind_ssbo("result_indices_buf", result_idx);
154 pass.draw(batch_cylinder);
156
157 manager.submit(pass);
158
159 /* Note: Expected values follows diagram shown in #142969. */
160
161 result_pos.read();
162 EXPECT_EQ(result_pos[0], 0.75f);
163 EXPECT_EQ(result_pos[1], 1.0f);
164 EXPECT_EQ(result_pos[2], 0.75f);
165 EXPECT_EQ(result_pos[3], 1.0f);
166 EXPECT_EQ(result_pos[4], 0.75f);
167 EXPECT_EQ(result_pos[5], 1.0f);
168 EXPECT_TRUE(isnan(result_pos[6]));
169 EXPECT_EQ(result_pos[7], 0.75f);
170 EXPECT_EQ(result_pos[8], 0.5f);
171 EXPECT_EQ(result_pos[9], 0.75f);
172 EXPECT_EQ(result_pos[10], 0.5f);
173 EXPECT_EQ(result_pos[11], 0.75f);
174 EXPECT_EQ(result_pos[12], 0.5f);
175 EXPECT_TRUE(isnan(result_pos[13]));
176 EXPECT_EQ(result_pos[14], 0.25f);
177 EXPECT_EQ(result_pos[15], 0.5f);
178 EXPECT_EQ(result_pos[16], 0.25f);
179 EXPECT_EQ(result_pos[17], 0.5f);
180 EXPECT_EQ(result_pos[18], 0.25f);
181 EXPECT_EQ(result_pos[19], 0.5f);
182 EXPECT_TRUE(isnan(result_pos[20]));
183 EXPECT_EQ(result_pos[21], 0.25f);
184 EXPECT_EQ(result_pos[22], 0.0f);
185 EXPECT_EQ(result_pos[23], 0.25f);
186 EXPECT_EQ(result_pos[24], 0.0f);
187 EXPECT_EQ(result_pos[25], 0.25f);
188 EXPECT_EQ(result_pos[26], 0.0f);
189 EXPECT_TRUE(isnan(result_pos[27]));
190 EXPECT_EQ(result_pos[28], 1.0f);
191 EXPECT_EQ(result_pos[29], 0.0f);
192 EXPECT_EQ(result_pos[30], 1.0f);
193 EXPECT_EQ(result_pos[31], 0.0f);
194 EXPECT_EQ(result_pos[32], 1.0f);
195 EXPECT_EQ(result_pos[33], 0.0f);
196 EXPECT_TRUE(isnan(result_pos[34]));
197 EXPECT_EQ(result_pos[35], 1.0f);
198 EXPECT_EQ(result_pos[36], 2.0f);
199 EXPECT_EQ(result_pos[37], 1.0f);
200 EXPECT_EQ(result_pos[38], 2.0f);
201 EXPECT_EQ(result_pos[39], 1.0f);
202 EXPECT_EQ(result_pos[40], 2.0f);
203 EXPECT_TRUE(isnan(result_pos[41]));
204
205 result_idx.read();
206 /* x: point_id, y: curve_id, z: curve_segment, w: azimuthal_offset */
207 EXPECT_EQ(result_idx[0], int4(1, 0, 1, -1));
208 EXPECT_EQ(result_idx[1], int4(0, 0, 0, -1));
209 EXPECT_EQ(result_idx[2], int4(1, 0, 1, 0));
210 EXPECT_EQ(result_idx[3], int4(0, 0, 0, 0));
211 EXPECT_EQ(result_idx[4], int4(1, 0, 1, 1));
212 EXPECT_EQ(result_idx[5], int4(0, 0, 0, 1));
213 EXPECT_EQ(result_idx[6], int4(0, 0, 0, 2));
214
215 EXPECT_EQ(result_idx[7], int4(1, 0, 1, -1));
216 EXPECT_EQ(result_idx[8], int4(2, 0, 2, -1));
217 EXPECT_EQ(result_idx[9], int4(1, 0, 1, 0));
218 EXPECT_EQ(result_idx[10], int4(2, 0, 2, 0));
219 EXPECT_EQ(result_idx[11], int4(1, 0, 1, 1));
220 EXPECT_EQ(result_idx[12], int4(2, 0, 2, 1));
221 EXPECT_EQ(result_idx[13], int4(1, 0, 1, 2));
222
223 EXPECT_EQ(result_idx[14], int4(3, 0, 3, -1));
224 EXPECT_EQ(result_idx[15], int4(2, 0, 2, -1));
225 EXPECT_EQ(result_idx[16], int4(3, 0, 3, 0));
226 EXPECT_EQ(result_idx[17], int4(2, 0, 2, 0));
227 EXPECT_EQ(result_idx[18], int4(3, 0, 3, 1));
228 EXPECT_EQ(result_idx[19], int4(2, 0, 2, 1));
229 EXPECT_EQ(result_idx[20], int4(2, 0, 2, 2));
230
231 EXPECT_EQ(result_idx[21], int4(3, 0, 3, -1));
232 EXPECT_EQ(result_idx[22], int4(4, 0, 4, -1));
233 EXPECT_EQ(result_idx[23], int4(3, 0, 3, 0));
234 EXPECT_EQ(result_idx[24], int4(4, 0, 4, 0));
235 EXPECT_EQ(result_idx[25], int4(3, 0, 3, 1));
236 EXPECT_EQ(result_idx[26], int4(4, 0, 4, 1));
237 EXPECT_EQ(result_idx[27], int4(3, 0, 3, 2));
238
239 EXPECT_EQ(result_idx[28], int4(6, 1, 1, -1));
240 EXPECT_EQ(result_idx[29], int4(5, 1, 0, -1));
241 EXPECT_EQ(result_idx[30], int4(6, 1, 1, 0));
242 EXPECT_EQ(result_idx[31], int4(5, 1, 0, 0));
243 EXPECT_EQ(result_idx[32], int4(6, 1, 1, 1));
244 EXPECT_EQ(result_idx[33], int4(5, 1, 0, 1));
245 EXPECT_EQ(result_idx[34], int4(5, 1, 0, 2));
246
247 EXPECT_EQ(result_idx[35], int4(6, 1, 1, -1));
248 EXPECT_EQ(result_idx[36], int4(7, 1, 2, -1));
249 EXPECT_EQ(result_idx[37], int4(6, 1, 1, 0));
250 EXPECT_EQ(result_idx[38], int4(7, 1, 2, 0));
251 EXPECT_EQ(result_idx[39], int4(6, 1, 1, 1));
252 EXPECT_EQ(result_idx[40], int4(7, 1, 2, 1));
253 EXPECT_EQ(result_idx[41], int4(6, 1, 1, 2));
254 }
255
257
259 GPU_BATCH_DISCARD_SAFE(batch_ribbon);
260 GPU_BATCH_DISCARD_SAFE(batch_cylinder);
261 GPU_VERTBUF_DISCARD_SAFE(indirection_ribbon_buf);
262 GPU_VERTBUF_DISCARD_SAFE(indirection_cylinder_buf);
263 GPU_VERTBUF_DISCARD_SAFE(pos_rad_buf);
264}
265DRAW_TEST(draw_curves_lib)
266
268{
269 Manager manager;
270
271 gpu::Shader *sh = GPU_shader_create_from_info_name("draw_curves_topology");
272
273 struct IntBuf {
274 int data;
276 };
277 gpu::VertBuf *curve_offsets_buf = GPU_vertbuf_create_with_format(IntBuf::format());
278 curve_offsets_buf->allocate(4);
279 curve_offsets_buf->data<int>().copy_from({0, 5, 8, 10});
280
281 {
282 StorageArrayBuffer<int, 512> indirection_buf;
283 indirection_buf.clear_to_zero();
284
285 PassSimple pass("Ribbon Curves");
286 pass.init();
287 pass.shader_set(sh);
288 pass.bind_ssbo("evaluated_offsets_buf", curve_offsets_buf);
289 pass.bind_ssbo("curves_cyclic_buf", curve_offsets_buf);
290 pass.bind_ssbo("indirection_buf", indirection_buf);
291 pass.push_constant("curves_start", 0);
292 pass.push_constant("curves_count", 3);
293 pass.push_constant("is_ribbon_topology", true);
294 pass.push_constant("use_cyclic", false);
295 pass.dispatch(1);
297
298 manager.submit(pass);
299
300 /* Note: Expected values follows diagram shown in #142969. */
301 indirection_buf.read();
302
303 EXPECT_EQ(indirection_buf[0], 0);
304 EXPECT_EQ(indirection_buf[1], -1);
305 EXPECT_EQ(indirection_buf[2], -2);
306 EXPECT_EQ(indirection_buf[3], -3);
307 EXPECT_EQ(indirection_buf[4], -4);
308 EXPECT_EQ(indirection_buf[5], 0x7FFFFFFF);
309 EXPECT_EQ(indirection_buf[6], 1);
310 EXPECT_EQ(indirection_buf[7], -1);
311 EXPECT_EQ(indirection_buf[8], -2);
312 EXPECT_EQ(indirection_buf[9], 0x7FFFFFFF);
313 EXPECT_EQ(indirection_buf[10], 2);
314 EXPECT_EQ(indirection_buf[11], -1);
315 EXPECT_EQ(indirection_buf[12], 0x7FFFFFFF);
316 /* Ensure the rest of the buffer is untouched. */
317 EXPECT_EQ(indirection_buf[13], 0);
318 EXPECT_EQ(indirection_buf[14], 0);
319 }
320
321 {
322 StorageArrayBuffer<int, 512> indirection_buf;
323 indirection_buf.clear_to_zero();
324
325 PassSimple pass("Cylinder Curves");
326 pass.init();
327 pass.shader_set(sh);
328 pass.bind_ssbo("evaluated_offsets_buf", curve_offsets_buf);
329 pass.bind_ssbo("curves_cyclic_buf", curve_offsets_buf);
330 pass.bind_ssbo("indirection_buf", indirection_buf);
331 pass.push_constant("curves_start", 0);
332 pass.push_constant("curves_count", 3);
333 pass.push_constant("is_ribbon_topology", false);
334 pass.push_constant("use_cyclic", false);
335 pass.dispatch(1);
337
338 manager.submit(pass);
339
340 /* Note: Expected values follows diagram shown in #142969. */
341 indirection_buf.read();
342
343 EXPECT_EQ(indirection_buf[0], 0);
344 EXPECT_EQ(indirection_buf[1], -1);
345 EXPECT_EQ(indirection_buf[2], -2);
346 EXPECT_EQ(indirection_buf[3], -3);
347 EXPECT_EQ(indirection_buf[4], 1);
348 EXPECT_EQ(indirection_buf[5], -1);
349 EXPECT_EQ(indirection_buf[6], 2);
350 /* Ensure the rest of the buffer is untouched. */
351 EXPECT_EQ(indirection_buf[7], 0);
352 EXPECT_EQ(indirection_buf[8], 0);
353 }
354
356
358 GPU_VERTBUF_DISCARD_SAFE(curve_offsets_buf);
359}
360DRAW_TEST(draw_curves_topology)
361
363{
364 Manager manager;
365
366 gpu::Shader *sh = GPU_shader_create_from_info_name("draw_curves_interpolate_position");
368 "draw_curves_evaluate_length_intercept");
369
370 const int curve_resolution = 2;
371
372 const Vector<int> evaluated_offsets = {0, 5, 8};
373
374 struct IntBuf {
375 int data;
377 };
378 gpu::VertBuf *points_by_curve_buf = GPU_vertbuf_create_with_format(IntBuf::format());
379 points_by_curve_buf->allocate(3);
380 points_by_curve_buf->data<int>().copy_from({0, 3, 5});
381
382 gpu::VertBuf *curves_type_buf = GPU_vertbuf_create_with_format(IntBuf::format());
383 curves_type_buf->allocate(1);
384 curves_type_buf->data<char>().copy_from({CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_CATMULL_ROM, 0, 0});
385
386 gpu::VertBuf *curves_resolution_buf = GPU_vertbuf_create_with_format(IntBuf::format());
387 curves_resolution_buf->allocate(2);
388 curves_resolution_buf->data<int>().copy_from({curve_resolution, curve_resolution});
389
390 gpu::VertBuf *evaluated_points_by_curve_buf = GPU_vertbuf_create_with_format(IntBuf::format());
391 evaluated_points_by_curve_buf->allocate(3);
392 evaluated_points_by_curve_buf->data<int>().copy_from(evaluated_offsets);
393
394 const Vector<float> points_radius = {1.0f, 0.5f, 0.0f, 0.0f, 2.0f};
395 const Vector<float3> positions = {
396 float3{1.0f}, float3{0.5f}, float3{0.0f}, float3{0.0f}, float3{2.0f}};
397
398 struct Position {
399 float3 pos;
401 };
403 Position::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
404 positions_buf->allocate(positions.size());
405 positions_buf->data<float3>().copy_from(positions);
406
407 struct Radius {
408 float rad;
409 GPU_VERTEX_FORMAT_FUNC(Radius, rad);
410 };
411 gpu::VertBuf *radii_buf = GPU_vertbuf_create_with_format_ex(Radius::format(),
413 radii_buf->allocate(points_radius.size());
414 radii_buf->data<float>().copy_from(points_radius);
415
416 {
417 StorageArrayBuffer<float4, 512> evaluated_positions_radii_buf;
418 StorageArrayBuffer<float, 512> evaluated_time_buf;
419 StorageArrayBuffer<float, 512> curves_length_buf;
420 evaluated_positions_radii_buf.clear_to_zero();
421 evaluated_time_buf.clear_to_zero();
422 curves_length_buf.clear_to_zero();
423
424 PassSimple pass("Curves Interpolation Catmull Rom");
425 pass.init();
426 pass.specialize_constant(sh, "evaluated_type", int(CURVE_TYPE_CATMULL_ROM));
427 pass.shader_set(sh);
428 pass.bind_ssbo(POINTS_BY_CURVES_SLOT, points_by_curve_buf);
429 pass.bind_ssbo(CURVE_TYPE_SLOT, curves_type_buf);
430 pass.bind_ssbo(CURVE_RESOLUTION_SLOT, curves_resolution_buf);
431 pass.bind_ssbo(EVALUATED_POINT_SLOT, evaluated_points_by_curve_buf);
432 pass.bind_ssbo(POINT_POSITIONS_SLOT, positions_buf);
433 pass.bind_ssbo(POINT_RADII_SLOT, radii_buf);
434 pass.bind_ssbo(EVALUATED_POS_RAD_SLOT, evaluated_positions_radii_buf);
435 pass.push_constant("use_cyclic", false);
436 pass.bind_ssbo(CURVE_CYCLIC_SLOT, evaluated_points_by_curve_buf); /* Dummy, not used. */
437 /* Dummy, not used for Catmull-Rom. */
438 pass.bind_ssbo(HANDLES_POS_LEFT_SLOT, evaluated_points_by_curve_buf);
439 pass.bind_ssbo(HANDLES_POS_RIGHT_SLOT, evaluated_points_by_curve_buf);
440 pass.bind_ssbo(BEZIER_OFFSETS_SLOT, evaluated_points_by_curve_buf);
441 pass.push_constant("curves_start", 0);
442 pass.push_constant("curves_count", 2);
443 pass.push_constant("transform", float4x4::identity());
444 pass.dispatch(1);
446 pass.shader_set(sh_length);
447 pass.bind_ssbo(EVALUATED_POINT_SLOT, evaluated_points_by_curve_buf);
448 pass.bind_ssbo(EVALUATED_POS_RAD_SLOT, evaluated_positions_radii_buf);
449 pass.bind_ssbo(EVALUATED_TIME_SLOT, evaluated_time_buf);
450 pass.bind_ssbo(CURVES_LENGTH_SLOT, curves_length_buf);
451 pass.push_constant("curves_start", 0);
452 pass.push_constant("curves_count", 2);
453 pass.push_constant("use_cyclic", false);
454 pass.dispatch(1);
456
457 manager.submit(pass);
458
459 evaluated_positions_radii_buf.read();
460 evaluated_time_buf.read();
461 curves_length_buf.read();
462
463 Vector<float> interp_data;
464 interp_data.resize(8);
465
467 GSpan(points_radius.as_span().slice(0, 3)),
468 false,
469 curve_resolution,
470 GMutableSpan(interp_data.as_mutable_span().slice(0, 5)));
471
473 GSpan(points_radius.as_span().slice(3, 2)),
474 false,
475 curve_resolution,
476 GMutableSpan(interp_data.as_mutable_span().slice(5, 3)));
477
478 EXPECT_EQ(evaluated_positions_radii_buf[0], float4(interp_data[0]));
479 EXPECT_EQ(evaluated_positions_radii_buf[1], float4(interp_data[1]));
480 EXPECT_EQ(evaluated_positions_radii_buf[2], float4(interp_data[2]));
481 EXPECT_EQ(evaluated_positions_radii_buf[3], float4(interp_data[3]));
482 EXPECT_EQ(evaluated_positions_radii_buf[4], float4(interp_data[4]));
483 EXPECT_EQ(evaluated_positions_radii_buf[5], float4(interp_data[5]));
484 EXPECT_EQ(evaluated_positions_radii_buf[6], float4(interp_data[6]));
485 EXPECT_EQ(evaluated_positions_radii_buf[7], float4(interp_data[7]));
486 /* Ensure the rest of the buffer is untouched. */
487 EXPECT_EQ(evaluated_positions_radii_buf[8], float4(0.0));
488
489 EXPECT_FLOAT_EQ(curves_length_buf[0], numbers::sqrt3);
490 EXPECT_FLOAT_EQ(curves_length_buf[1], 2.0f * numbers::sqrt3);
491
492 EXPECT_FLOAT_EQ(evaluated_time_buf[0], 0.0f);
493 EXPECT_FLOAT_EQ(evaluated_time_buf[1], 0.218749985f);
494 EXPECT_FLOAT_EQ(evaluated_time_buf[2], 0.5f);
495 EXPECT_FLOAT_EQ(evaluated_time_buf[3], 0.78125f);
496 EXPECT_FLOAT_EQ(evaluated_time_buf[4], 1.0f);
497 EXPECT_FLOAT_EQ(evaluated_time_buf[5], 0.0f);
498 EXPECT_FLOAT_EQ(evaluated_time_buf[6], 0.5f);
499 EXPECT_FLOAT_EQ(evaluated_time_buf[7], 1.0f);
500 /* Ensure the rest of the buffer is untouched. */
501 EXPECT_EQ(evaluated_time_buf[8], 0.0f);
502 }
503
504 const Vector<float3> handle_pos_left = {
505 float3{0.0f}, float3{1.0f}, float3{-1.0f}, float3{1.0f}, float3{4.0f}};
506 const Vector<float3> handle_pos_right = {
507 float3{0.0f}, float3{-1.0f}, float3{1.0f}, float3{-1.0f}, float3{0.0f}};
508
509 gpu::VertBuf *handles_positions_left_buf = GPU_vertbuf_create_with_format_ex(
510 Position::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
511 handles_positions_left_buf->allocate(handle_pos_left.size());
512 handles_positions_left_buf->data<float3>().copy_from(handle_pos_left);
513
514 gpu::VertBuf *handles_positions_right_buf = GPU_vertbuf_create_with_format_ex(
515 Position::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
516 handles_positions_right_buf->allocate(handle_pos_right.size());
517 handles_positions_right_buf->data<float3>().copy_from(handle_pos_right);
518
519 const Vector<int> bezier_offsets = {0, 2, 4, 5, 0, 2, 3};
520
522 IntBuf::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
523 bezier_offsets_buf->allocate(bezier_offsets.size());
524 bezier_offsets_buf->data<int>().copy_from(bezier_offsets);
525
526 gpu::VertBuf *curves_type_bezier_buf = GPU_vertbuf_create_with_format(IntBuf::format());
527 curves_type_bezier_buf->allocate(1);
528 curves_type_bezier_buf->data<char>().copy_from({CURVE_TYPE_BEZIER, CURVE_TYPE_BEZIER, 0, 0});
529
530 {
531 StorageArrayBuffer<float4, 512> evaluated_positions_radii_buf;
532 StorageArrayBuffer<float, 512> evaluated_time_buf;
533 StorageArrayBuffer<float, 512> curves_length_buf;
534 evaluated_positions_radii_buf.clear_to_zero();
535 evaluated_time_buf.clear_to_zero();
536 curves_length_buf.clear_to_zero();
537
538 PassSimple pass("Curves Interpolation Bezier");
539 pass.init();
540 pass.specialize_constant(sh, "evaluated_type", int(CURVE_TYPE_BEZIER));
541 pass.shader_set(sh);
542 pass.bind_ssbo(POINTS_BY_CURVES_SLOT, points_by_curve_buf);
543 pass.bind_ssbo(CURVE_TYPE_SLOT, curves_type_bezier_buf);
544 pass.bind_ssbo(CURVE_RESOLUTION_SLOT, curves_resolution_buf);
545 pass.bind_ssbo(EVALUATED_POINT_SLOT, evaluated_points_by_curve_buf);
546 pass.bind_ssbo(POINT_POSITIONS_SLOT, positions_buf);
547 pass.bind_ssbo(POINT_RADII_SLOT, radii_buf);
548 pass.bind_ssbo(EVALUATED_POS_RAD_SLOT, evaluated_positions_radii_buf);
549 pass.push_constant("use_cyclic", false);
550 pass.bind_ssbo(CURVE_CYCLIC_SLOT, evaluated_points_by_curve_buf); /* Dummy, not used. */
551 pass.bind_ssbo(HANDLES_POS_LEFT_SLOT, handles_positions_left_buf);
552 pass.bind_ssbo(HANDLES_POS_RIGHT_SLOT, handles_positions_right_buf);
553 pass.bind_ssbo(BEZIER_OFFSETS_SLOT, bezier_offsets_buf);
554 pass.push_constant("curves_start", 0);
555 pass.push_constant("curves_count", 2);
556 pass.push_constant("transform", float4x4::identity());
557 pass.dispatch(1);
559 pass.shader_set(sh_length);
560 pass.bind_ssbo(EVALUATED_POINT_SLOT, evaluated_points_by_curve_buf);
561 pass.bind_ssbo(EVALUATED_POS_RAD_SLOT, evaluated_positions_radii_buf);
562 pass.bind_ssbo(EVALUATED_TIME_SLOT, evaluated_time_buf);
563 pass.bind_ssbo(CURVES_LENGTH_SLOT, curves_length_buf);
564 pass.push_constant("curves_start", 0);
565 pass.push_constant("curves_count", 2);
566 pass.push_constant("use_cyclic", false);
567 pass.dispatch(1);
569
570 manager.submit(pass);
571
572 evaluated_positions_radii_buf.read();
573 evaluated_time_buf.read();
574 curves_length_buf.read();
575
576 Vector<float3> interp_pos;
577 interp_pos.resize(8);
578
579 Vector<float> interp_rad;
580 interp_rad.resize(8);
581
582 {
583 const int curve_index = 0;
584 const IndexRange points(0, 3);
585 const IndexRange evaluated_points(0, 5);
586 const IndexRange offsets = bke::curves::per_curve_point_offsets_range(points, curve_index);
587
589 positions.as_span().slice(points),
590 handle_pos_left.as_span().slice(points),
591 handle_pos_right.as_span().slice(points),
592 bezier_offsets.as_span().slice(offsets),
593 interp_pos.as_mutable_span().slice(evaluated_points));
594
596 points_radius.as_span().slice(points),
597 bezier_offsets.as_span().slice(offsets),
598 interp_rad.as_mutable_span().slice(evaluated_points));
599 }
600 {
601 const int curve_index = 1;
602 const IndexRange points(3, 2);
603 const IndexRange evaluated_points(5, 3);
604 const IndexRange offsets = bke::curves::per_curve_point_offsets_range(points, curve_index);
605
607 positions.as_span().slice(points),
608 handle_pos_left.as_span().slice(points),
609 handle_pos_right.as_span().slice(points),
610 bezier_offsets.as_span().slice(offsets),
611 interp_pos.as_mutable_span().slice(evaluated_points));
612
614 points_radius.as_span().slice(points),
615 bezier_offsets.as_span().slice(offsets),
616 interp_rad.as_mutable_span().slice(evaluated_points));
617 }
618
619 EXPECT_EQ(evaluated_positions_radii_buf[0], float4(interp_pos[0], interp_rad[0]));
620 EXPECT_EQ(evaluated_positions_radii_buf[1], float4(interp_pos[1], interp_rad[1]));
621 EXPECT_EQ(evaluated_positions_radii_buf[2], float4(interp_pos[2], interp_rad[2]));
622 EXPECT_EQ(evaluated_positions_radii_buf[3], float4(interp_pos[3], interp_rad[3]));
623 EXPECT_EQ(evaluated_positions_radii_buf[4], float4(interp_pos[4], interp_rad[4]));
624 EXPECT_EQ(evaluated_positions_radii_buf[5], float4(interp_pos[5], interp_rad[5]));
625 EXPECT_EQ(evaluated_positions_radii_buf[6], float4(interp_pos[6], interp_rad[6]));
626 EXPECT_EQ(evaluated_positions_radii_buf[7], float4(interp_pos[7], interp_rad[7]));
627 /* Ensure the rest of the buffer is untouched. */
628 EXPECT_EQ(evaluated_positions_radii_buf[8], float4(0.0));
629
630 float curve_len[2] = {0.0f, 0.0f};
631 Vector<float> interp_time{0.0f};
632 interp_time.resize(8);
633 interp_time[0] = 0.0f;
634 for (int i : IndexRange(1, 4)) {
635 curve_len[0] += math::distance(interp_pos[i], interp_pos[i - 1]);
636 interp_time[i] = curve_len[0];
637 }
638 for (int i : IndexRange(1, 4)) {
639 interp_time[i] /= curve_len[0];
640 }
641 interp_time[5] = 0.0f;
642 for (int i : IndexRange(6, 2)) {
643 curve_len[1] += math::distance(interp_pos[i], interp_pos[i - 1]);
644 interp_time[i] = curve_len[1];
645 }
646 for (int i : IndexRange(6, 2)) {
647 interp_time[i] /= curve_len[1];
648 }
649
650 EXPECT_FLOAT_EQ(curves_length_buf[0], curve_len[0]);
651 EXPECT_FLOAT_EQ(curves_length_buf[1], curve_len[1]);
652
653 EXPECT_FLOAT_EQ(evaluated_time_buf[0], interp_time[0]);
654 EXPECT_FLOAT_EQ(evaluated_time_buf[1], interp_time[1]);
655 EXPECT_FLOAT_EQ(evaluated_time_buf[2], interp_time[2]);
656 EXPECT_FLOAT_EQ(evaluated_time_buf[3], interp_time[3]);
657 EXPECT_FLOAT_EQ(evaluated_time_buf[4], interp_time[4]);
658 EXPECT_FLOAT_EQ(evaluated_time_buf[5], interp_time[5]);
659 EXPECT_FLOAT_EQ(evaluated_time_buf[6], interp_time[6]);
660 EXPECT_FLOAT_EQ(evaluated_time_buf[7], interp_time[7]);
661 /* Ensure the rest of the buffer is untouched. */
662 EXPECT_EQ(evaluated_time_buf[8], 0.0f);
663 }
664
665 const bke::curves::nurbs::BasisCache basis_cache_c0 = {
666 {0.1f, 0.2f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f},
667 {0, 0, 0, 0, 0},
668 false,
669 };
670 const bke::curves::nurbs::BasisCache basis_cache_c1 = {
671 {0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 2.0f},
672 {0, 0, 0},
673 false,
674 };
675
676 Vector<int> basis_cache_offset;
677 Vector<uint32_t> basis_cache_packed;
678 {
679 basis_cache_offset.append(basis_cache_c0.invalid ? -1 : basis_cache_packed.size());
680 basis_cache_packed.extend(
681 Span{reinterpret_cast<const uint32_t *>(basis_cache_c0.start_indices.data()),
682 basis_cache_c0.start_indices.size()});
683 basis_cache_packed.extend(
684 Span{reinterpret_cast<const uint32_t *>(basis_cache_c0.weights.data()),
685 basis_cache_c0.weights.size()});
686
687 basis_cache_offset.append(basis_cache_c1.invalid ? -1 : basis_cache_packed.size());
688 basis_cache_packed.extend(
689 Span{reinterpret_cast<const uint32_t *>(basis_cache_c1.start_indices.data()),
690 basis_cache_c1.start_indices.size()});
691 basis_cache_packed.extend(
692 Span{reinterpret_cast<const uint32_t *>(basis_cache_c1.weights.data()),
693 basis_cache_c1.weights.size()});
694 }
695
696 /* Raw data. Shader reinterpret as float or int. */
698 IntBuf::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
699 basis_cache_buf->allocate(basis_cache_packed.size());
700 basis_cache_buf->data<uint>().copy_from(basis_cache_packed);
701
702 gpu::VertBuf *basis_cache_offset_buf = GPU_vertbuf_create_with_format_ex(
703 IntBuf::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
704 basis_cache_offset_buf->allocate(basis_cache_offset.size());
705 basis_cache_offset_buf->data<int>().copy_from(basis_cache_offset);
706
707 const Vector<int8_t> curves_order = {3, 2, /* Padding. */ 0, 0};
708
710 IntBuf::format(), GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
711 curves_order_buf->allocate(curves_order.size() / 4);
712 curves_order_buf->data<int>().copy_from(
713 Span<int>(reinterpret_cast<const int *>(curves_order.data()), curves_order.size() / 4));
714
715 const Vector<float> control_weights = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
716
717 gpu::VertBuf *control_weights_buf = GPU_vertbuf_create_with_format(Radius::format());
718 control_weights_buf->allocate(control_weights.size());
719 control_weights_buf->data<float>().copy_from(control_weights);
720
721 gpu::VertBuf *curves_type_nurbs_buf = GPU_vertbuf_create_with_format(IntBuf::format());
722 curves_type_nurbs_buf->allocate(1);
723 curves_type_nurbs_buf->data<char>().copy_from({CURVE_TYPE_NURBS, CURVE_TYPE_NURBS, 0, 0});
724
725 {
726 StorageArrayBuffer<float4, 512> evaluated_positions_radii_buf;
727 StorageArrayBuffer<float, 512> evaluated_time_buf;
728 StorageArrayBuffer<float, 512> curves_length_buf;
729 evaluated_positions_radii_buf.clear_to_zero();
730 evaluated_time_buf.clear_to_zero();
731 curves_length_buf.clear_to_zero();
732
733 PassSimple pass("Curves Interpolation Nurbs");
734 pass.init();
735 pass.specialize_constant(sh, "evaluated_type", int(CURVE_TYPE_NURBS));
736 pass.shader_set(sh);
737 pass.bind_ssbo(POINTS_BY_CURVES_SLOT, points_by_curve_buf);
738 pass.bind_ssbo(CURVE_TYPE_SLOT, curves_type_nurbs_buf);
739 pass.bind_ssbo(CURVE_RESOLUTION_SLOT, curves_resolution_buf);
740 pass.bind_ssbo(EVALUATED_POINT_SLOT, evaluated_points_by_curve_buf);
741 pass.bind_ssbo(POINT_POSITIONS_SLOT, positions_buf);
742 pass.bind_ssbo(POINT_RADII_SLOT, radii_buf);
743 pass.bind_ssbo(EVALUATED_POS_RAD_SLOT, evaluated_positions_radii_buf);
744 pass.push_constant("use_cyclic", false);
745 pass.bind_ssbo(CURVE_CYCLIC_SLOT, evaluated_points_by_curve_buf); /* Dummy, not used. */
746 pass.bind_ssbo(CURVES_ORDER_SLOT, curves_order_buf);
747 pass.bind_ssbo(BASIS_CACHE_SLOT, basis_cache_buf);
748 pass.bind_ssbo(CONTROL_WEIGHTS_SLOT, control_weights_buf);
749 pass.bind_ssbo(BASIS_CACHE_OFFSET_SLOT, basis_cache_offset_buf);
750 pass.push_constant("curves_start", 0);
751 pass.push_constant("curves_count", 2);
752 pass.push_constant("use_point_weight", true);
753 pass.push_constant("transform", float4x4::identity());
754 pass.dispatch(1);
756 pass.shader_set(sh_length);
757 pass.bind_ssbo(EVALUATED_POINT_SLOT, evaluated_points_by_curve_buf);
758 pass.bind_ssbo(EVALUATED_POS_RAD_SLOT, evaluated_positions_radii_buf);
759 pass.bind_ssbo(EVALUATED_TIME_SLOT, evaluated_time_buf);
760 pass.bind_ssbo(CURVES_LENGTH_SLOT, curves_length_buf);
761 pass.push_constant("curves_start", 0);
762 pass.push_constant("curves_count", 2);
763 pass.push_constant("use_cyclic", false);
764 pass.dispatch(1);
766
767 manager.submit(pass);
768
769 evaluated_positions_radii_buf.read();
770 evaluated_time_buf.read();
771 curves_length_buf.read();
772
773 Vector<float3> interp_pos;
774 interp_pos.resize(8);
775
776 Vector<float> interp_rad;
777 interp_rad.resize(8);
778
779 {
780 const int curve_index = 0;
781 const IndexRange points(0, 3);
782 const IndexRange evaluated_points(0, 5);
783
785 basis_cache_c0,
786 curves_order[curve_index],
787 control_weights.as_span().slice(points),
788 positions.as_span().slice(points),
789 interp_pos.as_mutable_span().slice(evaluated_points));
790
792 basis_cache_c0,
793 curves_order[curve_index],
794 control_weights.as_span().slice(points),
795 points_radius.as_span().slice(points),
796 interp_rad.as_mutable_span().slice(evaluated_points));
797 }
798 {
799 const int curve_index = 1;
800 const IndexRange points(3, 2);
801 const IndexRange evaluated_points(5, 3);
802
804 basis_cache_c1,
805 curves_order[curve_index],
806 control_weights.as_span().slice(points),
807 positions.as_span().slice(points),
808 interp_pos.as_mutable_span().slice(evaluated_points));
809
811 basis_cache_c1,
812 curves_order[curve_index],
813 control_weights.as_span().slice(points),
814 points_radius.as_span().slice(points),
815 interp_rad.as_mutable_span().slice(evaluated_points));
816 }
817
818 EXPECT_NEAR(evaluated_positions_radii_buf[0].x, interp_pos[0].x, 0.000001f);
819 EXPECT_NEAR(evaluated_positions_radii_buf[1].x, interp_pos[1].x, 0.000001f);
820 EXPECT_NEAR(evaluated_positions_radii_buf[2].x, interp_pos[2].x, 0.000001f);
821 EXPECT_NEAR(evaluated_positions_radii_buf[3].x, interp_pos[3].x, 0.000001f);
822 EXPECT_NEAR(evaluated_positions_radii_buf[4].x, interp_pos[4].x, 0.000001f);
823 EXPECT_NEAR(evaluated_positions_radii_buf[5].x, interp_pos[5].x, 0.000001f);
824 EXPECT_NEAR(evaluated_positions_radii_buf[6].x, interp_pos[6].x, 0.000001f);
825 EXPECT_NEAR(evaluated_positions_radii_buf[7].x, interp_pos[7].x, 0.000001f);
826
827 EXPECT_NEAR(evaluated_positions_radii_buf[0].w, interp_rad[0], 0.000001f);
828 EXPECT_NEAR(evaluated_positions_radii_buf[1].w, interp_rad[1], 0.000001f);
829 EXPECT_NEAR(evaluated_positions_radii_buf[2].w, interp_rad[2], 0.000001f);
830 EXPECT_NEAR(evaluated_positions_radii_buf[3].w, interp_rad[3], 0.000001f);
831 EXPECT_NEAR(evaluated_positions_radii_buf[4].w, interp_rad[4], 0.000001f);
832 EXPECT_NEAR(evaluated_positions_radii_buf[5].w, interp_rad[5], 0.000001f);
833 EXPECT_NEAR(evaluated_positions_radii_buf[6].w, interp_rad[6], 0.000001f);
834 EXPECT_NEAR(evaluated_positions_radii_buf[7].w, interp_rad[7], 0.000001f);
835 /* Ensure the rest of the buffer is untouched. */
836 EXPECT_EQ(evaluated_positions_radii_buf[8], float4(0.0));
837
838 float curve_len[2] = {0.0f, 0.0f};
839 Vector<float> interp_time{0.0f};
840 interp_time.resize(8);
841 interp_time[0] = 0.0f;
842 for (int i : IndexRange(1, 4)) {
843 curve_len[0] += math::distance(interp_pos[i], interp_pos[i - 1]);
844 interp_time[i] = curve_len[0];
845 }
846 for (int i : IndexRange(1, 4)) {
847 interp_time[i] /= curve_len[0];
848 }
849 interp_time[5] = 0.0f;
850 for (int i : IndexRange(6, 2)) {
851 curve_len[1] += math::distance(interp_pos[i], interp_pos[i - 1]);
852 interp_time[i] = curve_len[1];
853 }
854 for (int i : IndexRange(6, 2)) {
855 interp_time[i] /= curve_len[1];
856 }
857
858 EXPECT_NEAR(curves_length_buf[0], curve_len[0], 0.000001f);
859 EXPECT_NEAR(curves_length_buf[1], curve_len[1], 0.000001f);
860
861 EXPECT_EQ(evaluated_time_buf[0], interp_time[0]);
862 EXPECT_NEAR(evaluated_time_buf[1], interp_time[1], 0.000001f);
863 EXPECT_NEAR(evaluated_time_buf[2], interp_time[2], 0.000001f);
864 EXPECT_NEAR(evaluated_time_buf[3], interp_time[3], 0.000001f);
865 EXPECT_NEAR(evaluated_time_buf[4], interp_time[4], 0.000001f);
866 EXPECT_EQ(evaluated_time_buf[5], interp_time[5]);
867 EXPECT_NEAR(evaluated_time_buf[6], interp_time[6], 0.000001f);
868 EXPECT_NEAR(evaluated_time_buf[7], interp_time[7], 0.000001f);
869 /* Ensure the rest of the buffer is untouched. */
870 EXPECT_EQ(evaluated_time_buf[8], 0.0f);
871 }
872
874
876 GPU_SHADER_FREE_SAFE(sh_length);
877 GPU_VERTBUF_DISCARD_SAFE(points_by_curve_buf);
878 GPU_VERTBUF_DISCARD_SAFE(curves_type_buf);
879 GPU_VERTBUF_DISCARD_SAFE(curves_type_bezier_buf);
880 GPU_VERTBUF_DISCARD_SAFE(curves_type_nurbs_buf);
881 GPU_VERTBUF_DISCARD_SAFE(curves_resolution_buf);
882 GPU_VERTBUF_DISCARD_SAFE(evaluated_points_by_curve_buf);
883 GPU_VERTBUF_DISCARD_SAFE(positions_buf);
884 GPU_VERTBUF_DISCARD_SAFE(radii_buf);
885 GPU_VERTBUF_DISCARD_SAFE(handles_positions_left_buf);
886 GPU_VERTBUF_DISCARD_SAFE(handles_positions_right_buf);
887 GPU_VERTBUF_DISCARD_SAFE(bezier_offsets_buf);
888 GPU_VERTBUF_DISCARD_SAFE(basis_cache_buf);
889 GPU_VERTBUF_DISCARD_SAFE(basis_cache_offset_buf);
890 GPU_VERTBUF_DISCARD_SAFE(curves_order_buf);
891 GPU_VERTBUF_DISCARD_SAFE(control_weights_buf);
892}
893DRAW_TEST(draw_curves_interpolate_position)
894
896{
897 Manager manager;
898
899 const int curve_resolution = 2;
900
901 const Vector<int> curves_to_point = {0, 3, 5, 7};
902 const Vector<int> evaluated_offsets = {0, 5, 8, 11};
903
904 struct IntBuf {
905 int data;
907 };
908 gpu::VertBuf *points_by_curve_buf = GPU_vertbuf_create_with_format(IntBuf::format());
909 points_by_curve_buf->allocate(curves_to_point.size());
910 points_by_curve_buf->data<int>().copy_from(curves_to_point);
911
912 gpu::VertBuf *curves_type_buf = GPU_vertbuf_create_with_format(IntBuf::format());
913 curves_type_buf->allocate(1);
914 curves_type_buf->data<char>().copy_from(
916
917 gpu::VertBuf *curves_resolution_buf = GPU_vertbuf_create_with_format(IntBuf::format());
918 curves_resolution_buf->allocate(3);
919 curves_resolution_buf->data<int>().copy_from(
920 {curve_resolution, curve_resolution, curve_resolution});
921
922 gpu::VertBuf *evaluated_points_by_curve_buf = GPU_vertbuf_create_with_format(IntBuf::format());
923 evaluated_points_by_curve_buf->allocate(evaluated_offsets.size());
924 evaluated_points_by_curve_buf->data<int>().copy_from(evaluated_offsets);
925
926 /* Attributes. */
927
928 const Vector<float4> attr_float4 = {float4(1.0f, 0.5f, 0.0f, 0.5f),
929 float4(0.5f, 0.0f, 0.0f, 4.0f),
930 float4(0.0f, 0.0f, 2.0f, 4.0f),
931 float4(2.0f, 3.0f, 4.0f, 7.0f),
932 float4(3.0f, 4.0f, 3.0f, 4.0f),
933 float4(2.0f, 2.0f, 3.0f, 4.0f),
934 float4(4.0f, 5.0f, 6.0f, 7.0f)};
935 const Vector<float3> attr_float3 =
936 attr_float4.as_span().cast<float>().take_front(attr_float4.size() * 3).cast<float3>();
937 const Vector<float2> attr_float2 =
938 attr_float4.as_span().cast<float>().take_front(attr_float4.size() * 2).cast<float2>();
939 const Vector<float> attr_float = attr_float4.as_span().cast<float>().take_front(
940 attr_float4.size());
941
942 struct Float4 {
943 float4 value;
944 GPU_VERTEX_FORMAT_FUNC(Float4, value);
945 };
946 gpu::VertBuf *attribute_float4_buf = GPU_vertbuf_create_with_format(Float4::format());
947 attribute_float4_buf->allocate(attr_float4.size());
948 attribute_float4_buf->data<float4>().copy_from(attr_float4);
949
950 struct Float3 {
951 float3 value;
952 GPU_VERTEX_FORMAT_FUNC(Float3, value);
953 };
954 gpu::VertBuf *attribute_float3_buf = GPU_vertbuf_create_with_format(Float3::format());
955 attribute_float3_buf->allocate(attr_float4.size());
956 attribute_float3_buf->data<float3>().copy_from(attr_float3);
957
958 struct Float2 {
959 float2 value;
960 GPU_VERTEX_FORMAT_FUNC(Float2, value);
961 };
962 gpu::VertBuf *attribute_float2_buf = GPU_vertbuf_create_with_format(Float2::format());
963 attribute_float2_buf->allocate(attr_float4.size());
964 attribute_float2_buf->data<float2>().copy_from(attr_float2);
965
966 struct Float {
967 float value;
969 };
970 gpu::VertBuf *attribute_float_buf = GPU_vertbuf_create_with_format(Float::format());
971 attribute_float_buf->allocate(attr_float4.size());
972 attribute_float_buf->data<float>().copy_from(attr_float);
973
974 /* Nurbs. */
975
976 const bke::curves::nurbs::BasisCache basis_cache_c0 = {
977 {0.1f, 0.2f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f},
978 {0, 0, 0, 0, 0},
979 false,
980 };
981
982 Vector<int> basis_cache_offset;
983 Vector<uint32_t> basis_cache_packed;
984 {
985 basis_cache_offset.append(basis_cache_c0.invalid ? -1 : basis_cache_packed.size());
986 basis_cache_packed.extend(
987 Span{reinterpret_cast<const uint32_t *>(basis_cache_c0.start_indices.data()),
988 basis_cache_c0.start_indices.size()});
989 basis_cache_packed.extend(
990 Span{reinterpret_cast<const uint32_t *>(basis_cache_c0.weights.data()),
991 basis_cache_c0.weights.size()});
992
993 basis_cache_offset.append(-1);
994 basis_cache_offset.append(-1);
995 }
996
997 /* Raw data. Shader reinterpret as float or int. */
998 gpu::VertBuf *basis_cache_buf = GPU_vertbuf_create_with_format(IntBuf::format());
999 basis_cache_buf->allocate(basis_cache_packed.size());
1000 basis_cache_buf->data<uint>().copy_from(basis_cache_packed);
1001
1002 gpu::VertBuf *basis_cache_offset_buf = GPU_vertbuf_create_with_format(IntBuf::format());
1003 basis_cache_offset_buf->allocate(basis_cache_offset.size());
1004 basis_cache_offset_buf->data<int>().copy_from(basis_cache_offset);
1005
1006 const Vector<int8_t> curves_order = {3, 0, 0, /* Padding. */ 0};
1007
1008 gpu::VertBuf *curves_order_buf = GPU_vertbuf_create_with_format(IntBuf::format());
1009 curves_order_buf->allocate(curves_order.size() / 4);
1010 curves_order_buf->data<int>().copy_from(
1011 Span<int>(reinterpret_cast<const int *>(curves_order.data()), curves_order.size() / 4));
1012
1013 const Vector<float> control_weights = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
1014
1015 gpu::VertBuf *control_weights_buf = GPU_vertbuf_create_with_format(Float::format());
1016 control_weights_buf->allocate(control_weights.size());
1017 control_weights_buf->data<float>().copy_from(control_weights);
1018
1019 /* Bezier */
1020
1021 const Vector<float3> handle_pos_left = {
1022 float3{0.0f}, float3{1.0f}, float3{-1.0f}, float3{1.0f}, float3{4.0f}};
1023 const Vector<float3> handle_pos_right = {
1024 float3{0.0f}, float3{-1.0f}, float3{1.0f}, float3{-1.0f}, float3{0.0f}};
1025
1026 gpu::VertBuf *handles_positions_left_buf = GPU_vertbuf_create_with_format(Float3::format());
1027 handles_positions_left_buf->allocate(handle_pos_left.size());
1028 handles_positions_left_buf->data<float3>().copy_from(handle_pos_left);
1029
1030 gpu::VertBuf *handles_positions_right_buf = GPU_vertbuf_create_with_format(Float3::format());
1031 handles_positions_right_buf->allocate(handle_pos_right.size());
1032 handles_positions_right_buf->data<float3>().copy_from(handle_pos_right);
1033
1034 const Vector<int> bezier_offsets = {0, 2, 4, 5, 0, 2, 3};
1035
1036 gpu::VertBuf *bezier_offsets_buf = GPU_vertbuf_create_with_format(IntBuf::format());
1037 bezier_offsets_buf->allocate(bezier_offsets.size());
1038 bezier_offsets_buf->data<int>().copy_from(bezier_offsets);
1039
1040 auto dispatch =
1041 [&](const char *attr_type, gpu::VertBuf *attr_buf, gpu::StorageBuf *evaluated_attr_buf) {
1042 std::string pass_name = std::string("Curves ") + attr_type + " Interpolation";
1043 std::string sh_name = std::string("draw_curves_interpolate_") + attr_type + "_attribute";
1044 /* Make sure all references to the strings are deleted before the strings themselves. */
1045 {
1046 gpu::Shader *sh = GPU_shader_create_from_info_name(sh_name.c_str());
1047
1048 PassSimple pass(pass_name.c_str());
1049 pass.init();
1050 pass.specialize_constant(sh, "evaluated_type", int(CURVE_TYPE_CATMULL_ROM));
1051 pass.shader_set(sh);
1052 pass.bind_ssbo(POINTS_BY_CURVES_SLOT, points_by_curve_buf);
1053 pass.bind_ssbo(CURVE_TYPE_SLOT, curves_type_buf);
1054 pass.bind_ssbo(CURVE_CYCLIC_SLOT, curves_type_buf); /* Dummy, not used */
1055 pass.bind_ssbo(CURVE_RESOLUTION_SLOT, curves_resolution_buf);
1056 pass.bind_ssbo(EVALUATED_POINT_SLOT, evaluated_points_by_curve_buf);
1057 pass.bind_ssbo(POINT_ATTR_SLOT, attr_buf);
1058 pass.bind_ssbo(EVALUATED_ATTR_SLOT, evaluated_attr_buf);
1059 /* Dummy, not used for Catmull-Rom. */
1060 pass.bind_ssbo(HANDLES_POS_LEFT_SLOT, evaluated_points_by_curve_buf);
1061 pass.bind_ssbo(HANDLES_POS_RIGHT_SLOT, evaluated_points_by_curve_buf);
1062 pass.bind_ssbo(BEZIER_OFFSETS_SLOT, evaluated_points_by_curve_buf);
1063 pass.push_constant("use_cyclic", false);
1064 pass.push_constant("curves_start", 0);
1065 pass.push_constant("curves_count", 3);
1066 pass.dispatch(1);
1067 pass.specialize_constant(sh, "evaluated_type", int(CURVE_TYPE_BEZIER));
1068 pass.shader_set(sh);
1069 pass.bind_ssbo(HANDLES_POS_LEFT_SLOT, handles_positions_left_buf);
1070 pass.bind_ssbo(HANDLES_POS_RIGHT_SLOT, handles_positions_right_buf);
1071 pass.bind_ssbo(BEZIER_OFFSETS_SLOT, bezier_offsets_buf);
1072 pass.push_constant("use_cyclic", false);
1073 pass.push_constant("curves_start", 0);
1074 pass.push_constant("curves_count", 3);
1075 pass.dispatch(1);
1076 pass.specialize_constant(sh, "evaluated_type", int(CURVE_TYPE_NURBS));
1077 pass.shader_set(sh);
1078 pass.bind_ssbo(CURVES_ORDER_SLOT, curves_order_buf);
1079 pass.bind_ssbo(BASIS_CACHE_SLOT, basis_cache_buf);
1080 pass.bind_ssbo(CONTROL_WEIGHTS_SLOT, control_weights_buf);
1081 pass.bind_ssbo(BASIS_CACHE_OFFSET_SLOT, basis_cache_offset_buf);
1082 pass.push_constant("use_cyclic", false);
1083 pass.push_constant("curves_start", 0);
1084 pass.push_constant("curves_count", 3);
1085 pass.push_constant("use_point_weight", true);
1086 pass.dispatch(1);
1088
1089 manager.submit(pass);
1090
1092
1094 }
1095 };
1096
1097 {
1098 StorageArrayBuffer<float4, 512> evaluated_float4_buf;
1099 evaluated_float4_buf.clear_to_zero();
1100
1101 dispatch("float4", attribute_float4_buf, evaluated_float4_buf);
1102
1103 evaluated_float4_buf.read();
1104
1105 Vector<float4> interp_data;
1106 interp_data.resize(11);
1107
1108 OffsetIndices<int> curves_to_point_indices(curves_to_point.as_span());
1109 OffsetIndices<int> curves_to_eval_indices(evaluated_offsets.as_span());
1110 Span<ColorGeometry4f> in_attr = attr_float4.as_span().cast<ColorGeometry4f>();
1111 MutableSpan<ColorGeometry4f> out_attr = interp_data.as_mutable_span().cast<ColorGeometry4f>();
1112 {
1113 const int curve_index = 0;
1114 const IndexRange points = curves_to_point_indices[curve_index];
1115 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1117 curves_order[curve_index],
1118 control_weights.as_span().slice(points),
1119 in_attr.slice(points),
1120 out_attr.slice(evaluated_points));
1121 }
1122 {
1123 const int curve_index = 1;
1124 const IndexRange points = curves_to_point_indices[curve_index];
1125 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1126 const IndexRange offsets = bke::curves::per_curve_point_offsets_range(points, curve_index);
1128 bezier_offsets.as_span().slice(offsets),
1129 out_attr.slice(evaluated_points));
1130 }
1131 {
1132 const int curve_index = 2;
1133 const IndexRange points = curves_to_point_indices[curve_index];
1134 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1136 in_attr.slice(points), false, curve_resolution, out_attr.slice(evaluated_points));
1137 }
1138
1139 EXPECT_EQ(evaluated_float4_buf[0], float4(interp_data[0]));
1140 EXPECT_EQ(evaluated_float4_buf[1], float4(interp_data[1]));
1141 EXPECT_EQ(evaluated_float4_buf[2], float4(interp_data[2]));
1142 EXPECT_EQ(evaluated_float4_buf[3], float4(interp_data[3]));
1143 EXPECT_EQ(evaluated_float4_buf[4], float4(interp_data[4]));
1144 EXPECT_EQ(evaluated_float4_buf[5], float4(interp_data[5]));
1145 EXPECT_EQ(evaluated_float4_buf[6], float4(interp_data[6]));
1146 EXPECT_EQ(evaluated_float4_buf[7], float4(interp_data[7]));
1147 EXPECT_EQ(evaluated_float4_buf[8], float4(interp_data[8]));
1148 EXPECT_EQ(evaluated_float4_buf[9], float4(interp_data[9]));
1149 EXPECT_EQ(evaluated_float4_buf[10], float4(interp_data[10]));
1150 /* Ensure the rest of the buffer is untouched. */
1151 EXPECT_EQ(evaluated_float4_buf[11], float4(0.0));
1152 }
1153
1154 {
1155 StorageArrayBuffer<float3, 512> evaluated_float3_buf;
1156 evaluated_float3_buf.clear_to_zero();
1157
1158 dispatch("float3", attribute_float3_buf, evaluated_float3_buf);
1159
1160 evaluated_float3_buf.read();
1161
1162 Vector<float3> interp_data;
1163 interp_data.resize(11);
1164
1165 OffsetIndices<int> curves_to_point_indices(curves_to_point.as_span());
1166 OffsetIndices<int> curves_to_eval_indices(evaluated_offsets.as_span());
1167 Span<float3> in_attr = attr_float3.as_span();
1168 MutableSpan<float3> out_attr = interp_data.as_mutable_span();
1169 {
1170 const int curve_index = 0;
1171 const IndexRange points = curves_to_point_indices[curve_index];
1172 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1174 curves_order[curve_index],
1175 control_weights.as_span().slice(points),
1176 in_attr.slice(points),
1177 out_attr.slice(evaluated_points));
1178 }
1179 {
1180 const int curve_index = 1;
1181 const IndexRange points = curves_to_point_indices[curve_index];
1182 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1183 const IndexRange offsets = bke::curves::per_curve_point_offsets_range(points, curve_index);
1185 bezier_offsets.as_span().slice(offsets),
1186 out_attr.slice(evaluated_points));
1187 }
1188 {
1189 const int curve_index = 2;
1190 const IndexRange points = curves_to_point_indices[curve_index];
1191 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1193 in_attr.slice(points), false, curve_resolution, out_attr.slice(evaluated_points));
1194 }
1195
1196 EXPECT_EQ(evaluated_float3_buf[0], float3(interp_data[0]));
1197 EXPECT_EQ(evaluated_float3_buf[1], float3(interp_data[1]));
1198 EXPECT_EQ(evaluated_float3_buf[2], float3(interp_data[2]));
1199 EXPECT_EQ(evaluated_float3_buf[3], float3(interp_data[3]));
1200 EXPECT_EQ(evaluated_float3_buf[4], float3(interp_data[4]));
1201 EXPECT_EQ(evaluated_float3_buf[5], float3(interp_data[5]));
1202 EXPECT_EQ(evaluated_float3_buf[6], float3(interp_data[6]));
1203 EXPECT_EQ(evaluated_float3_buf[7], float3(interp_data[7]));
1204 EXPECT_EQ(evaluated_float3_buf[8], float3(interp_data[8]));
1205 EXPECT_EQ(evaluated_float3_buf[9], float3(interp_data[9]));
1206 EXPECT_EQ(evaluated_float3_buf[10], float3(interp_data[10]));
1207 /* Ensure the rest of the buffer is untouched. */
1208 EXPECT_EQ(evaluated_float3_buf[11], float3(0.0));
1209 }
1210
1211 {
1212 StorageArrayBuffer<float2, 512> evaluated_float2_buf;
1213 evaluated_float2_buf.clear_to_zero();
1214
1215 dispatch("float2", attribute_float2_buf, evaluated_float2_buf);
1216
1217 evaluated_float2_buf.read();
1218
1219 Vector<float2> interp_data;
1220 interp_data.resize(11);
1221
1222 OffsetIndices<int> curves_to_point_indices(curves_to_point.as_span());
1223 OffsetIndices<int> curves_to_eval_indices(evaluated_offsets.as_span());
1224 Span<float2> in_attr = attr_float2.as_span();
1225 MutableSpan<float2> out_attr = interp_data.as_mutable_span();
1226 {
1227 const int curve_index = 0;
1228 const IndexRange points = curves_to_point_indices[curve_index];
1229 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1231 curves_order[curve_index],
1232 control_weights.as_span().slice(points),
1233 in_attr.slice(points),
1234 out_attr.slice(evaluated_points));
1235 }
1236 {
1237 const int curve_index = 1;
1238 const IndexRange points = curves_to_point_indices[curve_index];
1239 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1240 const IndexRange offsets = bke::curves::per_curve_point_offsets_range(points, curve_index);
1242 bezier_offsets.as_span().slice(offsets),
1243 out_attr.slice(evaluated_points));
1244 }
1245 {
1246 const int curve_index = 2;
1247 const IndexRange points = curves_to_point_indices[curve_index];
1248 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1250 in_attr.slice(points), false, curve_resolution, out_attr.slice(evaluated_points));
1251 }
1252
1253 EXPECT_EQ(evaluated_float2_buf[0], float2(interp_data[0]));
1254 EXPECT_EQ(evaluated_float2_buf[1], float2(interp_data[1]));
1255 EXPECT_EQ(evaluated_float2_buf[2], float2(interp_data[2]));
1256 EXPECT_EQ(evaluated_float2_buf[3], float2(interp_data[3]));
1257 EXPECT_EQ(evaluated_float2_buf[4], float2(interp_data[4]));
1258 EXPECT_EQ(evaluated_float2_buf[5], float2(interp_data[5]));
1259 EXPECT_EQ(evaluated_float2_buf[6], float2(interp_data[6]));
1260 EXPECT_EQ(evaluated_float2_buf[7], float2(interp_data[7]));
1261 EXPECT_EQ(evaluated_float2_buf[8], float2(interp_data[8]));
1262 EXPECT_EQ(evaluated_float2_buf[9], float2(interp_data[9]));
1263 EXPECT_EQ(evaluated_float2_buf[10], float2(interp_data[10]));
1264 /* Ensure the rest of the buffer is untouched. */
1265 EXPECT_EQ(evaluated_float2_buf[11], float2(0.0));
1266 }
1267
1268 {
1269 StorageArrayBuffer<float, 512> evaluated_float_buf;
1270 evaluated_float_buf.clear_to_zero();
1271
1272 dispatch("float", attribute_float_buf, evaluated_float_buf);
1273
1274 evaluated_float_buf.read();
1275
1276 Vector<float> interp_data;
1277 interp_data.resize(11);
1278
1279 OffsetIndices<int> curves_to_point_indices(curves_to_point.as_span());
1280 OffsetIndices<int> curves_to_eval_indices(evaluated_offsets.as_span());
1281 Span<float> in_attr = attr_float.as_span();
1282 MutableSpan<float> out_attr = interp_data.as_mutable_span();
1283 {
1284 const int curve_index = 0;
1285 const IndexRange points = curves_to_point_indices[curve_index];
1286 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1288 curves_order[curve_index],
1289 control_weights.as_span().slice(points),
1290 in_attr.slice(points),
1291 out_attr.slice(evaluated_points));
1292 }
1293 {
1294 const int curve_index = 1;
1295 const IndexRange points = curves_to_point_indices[curve_index];
1296 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1297 const IndexRange offsets = bke::curves::per_curve_point_offsets_range(points, curve_index);
1299 bezier_offsets.as_span().slice(offsets),
1300 out_attr.slice(evaluated_points));
1301 }
1302 {
1303 const int curve_index = 2;
1304 const IndexRange points = curves_to_point_indices[curve_index];
1305 const IndexRange evaluated_points = curves_to_eval_indices[curve_index];
1307 in_attr.slice(points), false, curve_resolution, out_attr.slice(evaluated_points));
1308 }
1309
1310 EXPECT_EQ(evaluated_float_buf[0], float(interp_data[0]));
1311 EXPECT_EQ(evaluated_float_buf[1], float(interp_data[1]));
1312 EXPECT_EQ(evaluated_float_buf[2], float(interp_data[2]));
1313 EXPECT_EQ(evaluated_float_buf[3], float(interp_data[3]));
1314 EXPECT_EQ(evaluated_float_buf[4], float(interp_data[4]));
1315 EXPECT_EQ(evaluated_float_buf[5], float(interp_data[5]));
1316 EXPECT_EQ(evaluated_float_buf[6], float(interp_data[6]));
1317 EXPECT_EQ(evaluated_float_buf[7], float(interp_data[7]));
1318 EXPECT_EQ(evaluated_float_buf[8], float(interp_data[8]));
1319 EXPECT_EQ(evaluated_float_buf[9], float(interp_data[9]));
1320 EXPECT_EQ(evaluated_float_buf[10], float(interp_data[10]));
1321 /* Ensure the rest of the buffer is untouched. */
1322 EXPECT_EQ(evaluated_float_buf[11], float(0.0));
1323 }
1324
1325 GPU_VERTBUF_DISCARD_SAFE(points_by_curve_buf);
1326 GPU_VERTBUF_DISCARD_SAFE(curves_type_buf);
1327 GPU_VERTBUF_DISCARD_SAFE(curves_resolution_buf);
1328 GPU_VERTBUF_DISCARD_SAFE(evaluated_points_by_curve_buf);
1329 GPU_VERTBUF_DISCARD_SAFE(handles_positions_left_buf);
1330 GPU_VERTBUF_DISCARD_SAFE(handles_positions_right_buf);
1331 GPU_VERTBUF_DISCARD_SAFE(bezier_offsets_buf);
1332 GPU_VERTBUF_DISCARD_SAFE(basis_cache_buf);
1333 GPU_VERTBUF_DISCARD_SAFE(basis_cache_offset_buf);
1334 GPU_VERTBUF_DISCARD_SAFE(curves_order_buf);
1335 GPU_VERTBUF_DISCARD_SAFE(control_weights_buf);
1336 GPU_VERTBUF_DISCARD_SAFE(attribute_float4_buf);
1337 GPU_VERTBUF_DISCARD_SAFE(attribute_float3_buf);
1338 GPU_VERTBUF_DISCARD_SAFE(attribute_float2_buf);
1339 GPU_VERTBUF_DISCARD_SAFE(attribute_float_buf);
1340}
1341DRAW_TEST(draw_curves_interpolate_attributes)
1342
1343} // namespace blender::draw
Low-level operations for curves.
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
unsigned int uint
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:197
blender::gpu::Batch * GPU_batch_create_procedural(GPUPrimType primitive_type, int32_t vertex_count)
Definition gpu_batch.cc:83
@ GPU_PRIM_TRI_STRIP
#define GPU_SHADER_FREE_SAFE(shader)
blender::gpu::Shader * GPU_shader_create_from_info_name(const char *info_name)
void GPU_shader_unbind()
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
@ GPU_BARRIER_BUFFER_UPDATE
Definition GPU_state.hh:56
blender::gpu::VertBuf * GPU_vertbuf_create_with_format_ex(const GPUVertFormat &format, GPUUsageType usage)
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
@ GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY
#define GPU_VERTEX_FORMAT_FUNC(_VertT,...)
BMesh const char void * data
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
int64_t size() const
T * data()
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
int64_t size() const
void append(const T &value)
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
void extend(Span< T > array)
Span< T > as_span() const
void submit(PassSimple &pass, View &view)
void framebuffer_set(gpu::FrameBuffer **framebuffer)
void shader_set(gpu::Shader *shader)
void bind_texture(const char *name, gpu::Texture *texture, GPUSamplerState state=sampler_auto)
void specialize_constant(gpu::Shader *shader, const char *name, const float &data)
void dispatch(int group_len)
void barrier(GPUBarrier type)
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceIndexRange res_index={}, uint custom_id=0)
Definition draw_pass.hh:893
void bind_ubo(const char *name, gpu::UniformBuf *buffer)
void push_constant(const char *name, const float &data)
void bind_ssbo(const char *name, gpu::StorageBuf *buffer)
void allocate(uint vert_len)
MutableSpan< T > data()
#define HANDLES_POS_LEFT_SLOT
#define CONTROL_WEIGHTS_SLOT
#define BASIS_CACHE_OFFSET_SLOT
#define POINT_ATTR_SLOT
#define EVALUATED_ATTR_SLOT
#define CURVE_TYPE_SLOT
#define POINT_RADII_SLOT
#define BASIS_CACHE_SLOT
#define CURVES_ORDER_SLOT
#define POINTS_BY_CURVES_SLOT
#define EVALUATED_POS_RAD_SLOT
#define EVALUATED_TIME_SLOT
#define EVALUATED_POINT_SLOT
#define CURVES_LENGTH_SLOT
#define HANDLES_POS_RIGHT_SLOT
#define CURVE_CYCLIC_SLOT
#define BEZIER_OFFSETS_SLOT
#define POINT_POSITIONS_SLOT
#define CURVE_RESOLUTION_SLOT
#define DRAW_TEST(test_name)
uint pos
#define isnan
BLI_INLINE float fb(float length, float L)
void calculate_evaluated_positions(Span< float3 > positions, Span< float3 > handles_left, Span< float3 > handles_right, OffsetIndices< int > evaluated_offsets, MutableSpan< float3 > evaluated_positions)
void interpolate_to_evaluated(GSpan src, OffsetIndices< int > evaluated_offsets, GMutableSpan dst)
void interpolate_to_evaluated(GSpan src, bool cyclic, int resolution, GMutableSpan dst)
void interpolate_to_evaluated(const BasisCache &basis_cache, int8_t order, Span< float > control_weights, GSpan src, GMutableSpan dst)
IndexRange per_curve_point_offsets_range(const IndexRange points, const int curve_index)
detail::Pass< command::DrawCommandBuf > PassSimple
static void test_draw_curves_interpolate_attributes()
static void test_draw_curves_lib()
static void test_draw_curves_interpolate_position()
static void test_draw_curves_topology()
T distance(const T &a, const T &b)
VecBase< int32_t, 4 > int4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
i
Definition text_draw.cc:230