Blender V4.3
draw_cache_impl_particles.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "DRW_render.hh"
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_alloca.h"
16#include "BLI_ghash.h"
17#include "BLI_math_color.h"
18#include "BLI_math_vector.h"
19#include "BLI_string.h"
20#include "BLI_utildefines.h"
21
23#include "DNA_mesh_types.h"
24#include "DNA_meshdata_types.h"
25#include "DNA_modifier_types.h"
26#include "DNA_particle_types.h"
27
28#include "BKE_customdata.hh"
29#include "BKE_mesh.hh"
31#include "BKE_particle.h"
32#include "BKE_pointcache.h"
33
34#include "ED_particle.hh"
35
36#include "GPU_batch.hh"
37#include "GPU_capabilities.hh"
38#include "GPU_context.hh"
39#include "GPU_material.hh"
40
42
43#include "draw_cache_impl.hh" /* own include */
44#include "draw_hair_private.hh"
45
46namespace blender::draw {
47
49
50/* ---------------------------------------------------------------------- */
51/* Particle gpu::Batch Cache */
52
59
61 /* Object mode strands for hair and points for particle,
62 * strands for paths when in edit mode.
63 */
64 ParticleHairCache hair; /* Used for hair strands */
65 ParticlePointCache point; /* Used for particle points. */
66
67 /* Control points when in edit mode. */
69
71 gpu::Batch *edit_strands;
72
74 gpu::Batch *edit_inner_points;
76
78 gpu::Batch *edit_tip_points;
80
81 /* Settings to determine if cache is invalid. */
84};
85
86/* gpu::Batch cache management. */
87
93
95 float pos[3];
96 float selection;
97};
98
99static GPUVertFormat *edit_points_vert_format_get(uint *r_pos_id, uint *r_selection_id)
100{
101 static GPUVertFormat edit_point_format = {0};
102 static uint pos_id, selection_id;
103 if (edit_point_format.attr_len == 0) {
104 /* Keep in sync with EditStrandData */
105 pos_id = GPU_vertformat_attr_add(&edit_point_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
106 selection_id = GPU_vertformat_attr_add(
107 &edit_point_format, "selection", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
108 }
109 *r_pos_id = pos_id;
110 *r_selection_id = selection_id;
111 return &edit_point_format;
112}
113
115{
116 ParticleBatchCache *cache = static_cast<ParticleBatchCache *>(psys->batch_cache);
117
118 if (cache == nullptr) {
119 return false;
120 }
121
122 if (cache->is_dirty == false) {
123 return true;
124 }
125
126 return false;
127
128 return true;
129}
130
132{
133 ParticleBatchCache *cache = static_cast<ParticleBatchCache *>(psys->batch_cache);
134
135 if (!cache) {
136 cache = static_cast<ParticleBatchCache *>(
137 psys->batch_cache = MEM_callocN(sizeof(*cache), __func__));
138 }
139 else {
140 memset(cache, 0, sizeof(*cache));
141 }
142
143 cache->is_dirty = false;
144}
145
147{
148 if (!particle_batch_cache_valid(psys)) {
151 }
152 return static_cast<ParticleBatchCache *>(psys->batch_cache);
153}
154
156{
157 ParticleBatchCache *cache = static_cast<ParticleBatchCache *>(psys->batch_cache);
158 if (cache == nullptr) {
159 return;
160 }
161 switch (mode) {
163 cache->is_dirty = true;
164 break;
165 default:
166 BLI_assert(0);
167 }
168}
169
171{
172 GPU_BATCH_DISCARD_SAFE(point_cache->points);
173 GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
174}
175
177{
178 /* TODO: more granular update tagging. */
181
184
185 for (int i = 0; i < MAX_MTFACE; i++) {
187 DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]);
188 }
189 for (int i = 0; i < hair_cache->num_col_layers; i++) {
191 DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]);
192 }
193
194 for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
196 for (int j = 0; j < MAX_THICKRES; j++) {
197 GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]);
198 }
199 }
200
201 /* "Normal" legacy hairs */
202 GPU_BATCH_DISCARD_SAFE(hair_cache->hairs);
203 GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
205
206 MEM_SAFE_FREE(hair_cache->proc_col_buf);
207 MEM_SAFE_FREE(hair_cache->col_tex);
208 MEM_SAFE_FREE(hair_cache->col_layer_names);
209}
210
212{
213 ParticleBatchCache *cache = static_cast<ParticleBatchCache *>(psys->batch_cache);
214 if (!cache) {
215 return;
216 }
217
218 /* All memory allocated by `cache` must be freed. */
219
221
224
229}
230
236
238 const int num_path_cache_keys,
239 ParticleHairCache *hair_cache)
240{
241 for (int i = 0; i < num_path_cache_keys; i++) {
242 ParticleCacheKey *path = pathcache[i];
243 if (path->segments > 0) {
244 hair_cache->strands_len++;
245 hair_cache->elems_len += path->segments + 2;
246 hair_cache->point_len += path->segments + 1;
247 }
248 }
249}
250
252 ParticleSystem *psys,
253 ParticleHairCache *hair_cache)
254{
255 if ((hair_cache->pos != nullptr && hair_cache->indices != nullptr) ||
256 (hair_cache->proc_point_buf != nullptr))
257 {
258 return;
259 }
260
261 hair_cache->strands_len = 0;
262 hair_cache->elems_len = 0;
263 hair_cache->point_len = 0;
264
265 if (edit != nullptr && edit->pathcache != nullptr) {
266 count_cache_segment_keys(edit->pathcache, edit->totcached, hair_cache);
267 }
268 else {
269 if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
270 count_cache_segment_keys(psys->pathcache, psys->totpart, hair_cache);
271 }
272 if (psys->childcache) {
273 const int child_count = psys->totchild * psys->part->disp / 100;
274 count_cache_segment_keys(psys->childcache, child_count, hair_cache);
275 }
276 }
277}
278
279static void particle_pack_mcol(MCol *mcol, ushort r_scol[3])
280{
281 /* Convert to linear ushort and swizzle */
285}
286
287/* Used by parent particles and simple children. */
290 const int num_uv_layers,
291 const int parent_index,
292 const MTFace **mtfaces,
293 float (*r_uv)[2])
294{
295 if (psmd == nullptr) {
296 return;
297 }
298 const int emit_from = psmd->psys->part->from;
299 if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
300 return;
301 }
302 ParticleData *particle = &psys->particles[parent_index];
303 int num = particle->num_dmcache;
305 if (particle->num < psmd->mesh_final->totface_legacy) {
306 num = particle->num;
307 }
308 }
310 const MFace *mfaces = static_cast<const MFace *>(
312 if (UNLIKELY(mfaces == nullptr)) {
314 "A mesh with polygons should always have a generated 'CD_MFACE' layer!");
315 return;
316 }
317 const MFace *mface = &mfaces[num];
318 for (int j = 0; j < num_uv_layers; j++) {
319 psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]);
320 }
321 }
322}
323
326 const int num_col_layers,
327 const int parent_index,
328 const MCol **mcols,
329 MCol *r_mcol)
330{
331 if (psmd == nullptr) {
332 return;
333 }
334 const int emit_from = psmd->psys->part->from;
335 if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
336 return;
337 }
338 ParticleData *particle = &psys->particles[parent_index];
339 int num = particle->num_dmcache;
341 if (particle->num < psmd->mesh_final->totface_legacy) {
342 num = particle->num;
343 }
344 }
346 const MFace *mfaces = static_cast<const MFace *>(
348 if (UNLIKELY(mfaces == nullptr)) {
350 "A mesh with polygons should always have a generated 'CD_MFACE' layer!");
351 return;
352 }
353 const MFace *mface = &mfaces[num];
354 for (int j = 0; j < num_col_layers; j++) {
355 /* CustomDataLayer CD_MCOL has 4 structs per face. */
356 psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
357 }
358 }
359}
360
361/* Used by interpolated children. */
364 const int num_uv_layers,
365 const int child_index,
366 const MTFace **mtfaces,
367 float (*r_uv)[2])
368{
369 if (psmd == nullptr) {
370 return;
371 }
372 const int emit_from = psmd->psys->part->from;
373 if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
374 return;
375 }
376 ChildParticle *particle = &psys->child[child_index];
377 int num = particle->num;
378 if (num != DMCACHE_NOTFOUND) {
379 const MFace *mfaces = static_cast<const MFace *>(
381 const MFace *mface = &mfaces[num];
382 for (int j = 0; j < num_uv_layers; j++) {
383 psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]);
384 }
385 }
386}
387
390 const int num_col_layers,
391 const int child_index,
392 const MCol **mcols,
393 MCol *r_mcol)
394{
395 if (psmd == nullptr) {
396 return;
397 }
398 const int emit_from = psmd->psys->part->from;
399 if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
400 return;
401 }
402 ChildParticle *particle = &psys->child[child_index];
403 int num = particle->num;
404 if (num != DMCACHE_NOTFOUND) {
405 const MFace *mfaces = static_cast<const MFace *>(
407 const MFace *mface = &mfaces[num];
408 for (int j = 0; j < num_col_layers; j++) {
409 /* CustomDataLayer CD_MCOL has 4 structs per face. */
410 psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
411 }
412 }
413}
414
417 const bool is_simple,
418 const int num_uv_layers,
419 const int parent_index,
420 const int child_index,
421 const MTFace **mtfaces,
422 float (**r_parent_uvs)[2],
423 float (**r_uv)[2])
424{
425 if (psmd == nullptr) {
426 return;
427 }
428 if (is_simple) {
429 if (r_parent_uvs[parent_index] != nullptr) {
430 *r_uv = r_parent_uvs[parent_index];
431 }
432 else {
433 *r_uv = static_cast<float(*)[2]>(
434 MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs"));
435 }
436 }
437 else {
438 *r_uv = static_cast<float(*)[2]>(MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs"));
439 }
440 if (child_index == -1) {
441 /* Calculate UVs for parent particles. */
442 if (is_simple) {
443 r_parent_uvs[parent_index] = *r_uv;
444 }
445 particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
446 }
447 else {
448 /* Calculate UVs for child particles. */
449 if (!is_simple) {
450 particle_interpolate_children_uvs(psys, psmd, num_uv_layers, child_index, mtfaces, *r_uv);
451 }
452 else if (!r_parent_uvs[psys->child[child_index].parent]) {
453 r_parent_uvs[psys->child[child_index].parent] = *r_uv;
454 particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
455 }
456 }
457}
458
461 const bool is_simple,
462 const int num_col_layers,
463 const int parent_index,
464 const int child_index,
465 const MCol **mcols,
466 MCol **r_parent_mcol,
467 MCol **r_mcol)
468{
469 if (psmd == nullptr) {
470 return;
471 }
472 if (is_simple) {
473 if (r_parent_mcol[parent_index] != nullptr) {
474 *r_mcol = r_parent_mcol[parent_index];
475 }
476 else {
477 *r_mcol = static_cast<MCol *>(
478 MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol"));
479 }
480 }
481 else {
482 *r_mcol = static_cast<MCol *>(MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol"));
483 }
484 if (child_index == -1) {
485 /* Calculate MCols for parent particles. */
486 if (is_simple) {
487 r_parent_mcol[parent_index] = *r_mcol;
488 }
489 particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
490 }
491 else {
492 /* Calculate MCols for child particles. */
493 if (!is_simple) {
494 particle_interpolate_children_mcol(psys, psmd, num_col_layers, child_index, mcols, *r_mcol);
495 }
496 else if (!r_parent_mcol[psys->child[child_index].parent]) {
497 r_parent_mcol[psys->child[child_index].parent] = *r_mcol;
498 particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
499 }
500 }
501}
502
503/* Will return last filled index. */
510 ParticleCacheKey **path_cache,
511 const ParticleSource particle_source,
512 const int global_offset,
513 const int start_index,
514 const int num_path_keys,
515 const int num_uv_layers,
516 const int num_col_layers,
517 const MTFace **mtfaces,
518 const MCol **mcols,
519 uint *uv_id,
520 uint *col_id,
521 float (***r_parent_uvs)[2],
522 MCol ***r_parent_mcol,
525 ParticleHairCache *hair_cache)
526{
527 const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
528 const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
529 if (is_simple && *r_parent_uvs == nullptr) {
530 /* TODO(sergey): For edit mode it should be edit->totcached. */
531 *r_parent_uvs = static_cast<float(**)[2]>(
532 MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs"));
533 }
534 if (is_simple && *r_parent_mcol == nullptr) {
535 *r_parent_mcol = static_cast<MCol **>(
536 MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol"));
537 }
538 int curr_point = start_index;
539 for (int i = 0; i < num_path_keys; i++) {
540 ParticleCacheKey *path = path_cache[i];
541 if (path->segments <= 0) {
542 continue;
543 }
544 float tangent[3];
545 float(*uv)[2] = nullptr;
546 MCol *mcol = nullptr;
548 psmd,
549 is_simple,
550 num_col_layers,
551 is_child ? psys->child[i].parent : i,
552 is_child ? i : -1,
553 mcols,
554 *r_parent_mcol,
555 &mcol);
557 psmd,
558 is_simple,
559 num_uv_layers,
560 is_child ? psys->child[i].parent : i,
561 is_child ? i : -1,
562 mtfaces,
563 *r_parent_uvs,
564 &uv);
565 for (int j = 0; j < path->segments; j++) {
566 if (j == 0) {
567 sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
568 }
569 else {
570 sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
571 }
572 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[j].co);
573 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
574 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &i);
575 if (psmd != nullptr) {
576 for (int k = 0; k < num_uv_layers; k++) {
578 hair_cache->pos,
579 uv_id[k],
580 curr_point,
581 (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] : uv[k]);
582 }
583 for (int k = 0; k < num_col_layers; k++) {
584 /* TODO: Put the conversion outside the loop. */
585 ushort scol[4];
587 (is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] : &mcol[k],
588 scol);
589 GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
590 }
591 }
592 GPU_indexbuf_add_generic_vert(elb, curr_point);
593 curr_point++;
594 }
595 sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
596
597 int global_index = i + global_offset;
598 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[path->segments].co);
599 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
600 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &global_index);
601
602 if (psmd != nullptr) {
603 for (int k = 0; k < num_uv_layers; k++) {
604 GPU_vertbuf_attr_set(hair_cache->pos,
605 uv_id[k],
606 curr_point,
607 (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] :
608 uv[k]);
609 }
610 for (int k = 0; k < num_col_layers; k++) {
611 /* TODO: Put the conversion outside the loop. */
612 ushort scol[4];
613 particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] :
614 &mcol[k],
615 scol);
616 GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
617 }
618 if (!is_simple) {
619 MEM_freeN(uv);
620 MEM_freeN(mcol);
621 }
622 }
623 /* Finish the segment and add restart primitive. */
624 GPU_indexbuf_add_generic_vert(elb, curr_point);
626 curr_point++;
627 }
628 return curr_point;
629}
630
632 const int num_path_keys,
633 GPUVertBufRaw *attr_step,
634 GPUVertBufRaw *length_step)
635{
636 for (int i = 0; i < num_path_keys; i++) {
637 ParticleCacheKey *path = path_cache[i];
638 if (path->segments <= 0) {
639 continue;
640 }
641 float total_len = 0.0f;
642 float *co_prev = nullptr, *seg_data_first;
643 for (int j = 0; j <= path->segments; j++) {
644 float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
645 copy_v3_v3(seg_data, path[j].co);
646 if (co_prev) {
647 total_len += len_v3v3(co_prev, path[j].co);
648 }
649 else {
650 seg_data_first = seg_data;
651 }
652 seg_data[3] = total_len;
653 co_prev = path[j].co;
654 }
655 /* Assign length value. */
656 *(float *)GPU_vertbuf_raw_step(length_step) = total_len;
657 if (total_len > 0.0f) {
658 /* Divide by total length to have a [0-1] number. */
659 for (int j = 0; j <= path->segments; j++, seg_data_first += 4) {
660 seg_data_first[3] /= total_len;
661 }
662 }
663 }
664}
665
666static float particle_key_weight(const ParticleData *particle, int strand, float t)
667{
668 const ParticleData *part = particle + strand;
669 const HairKey *hkeys = part->hair;
670 float edit_key_seg_t = 1.0f / (part->totkey - 1);
671 if (t == 1.0) {
672 return hkeys[part->totkey - 1].weight;
673 }
674
675 float interp = t / edit_key_seg_t;
676 int index = int(interp);
677 interp -= floorf(interp); /* Time between 2 edit key */
678 float s1 = hkeys[index].weight;
679 float s2 = hkeys[index + 1].weight;
680 return s1 + interp * (s2 - s1);
681}
682
684 const PTCacheEdit * /*edit*/, /* nullptr for weight data */
685 const ParticleData *particle, /* nullptr for select data */
686 ParticleCacheKey **path_cache,
687 const int start_index,
688 const int num_path_keys,
690 GPUVertBufRaw *attr_step)
691{
692 int curr_point = start_index;
693 for (int i = 0; i < num_path_keys; i++) {
694 ParticleCacheKey *path = path_cache[i];
695 if (path->segments <= 0) {
696 continue;
697 }
698 for (int j = 0; j <= path->segments; j++) {
699 EditStrandData *seg_data = (EditStrandData *)GPU_vertbuf_raw_step(attr_step);
700 copy_v3_v3(seg_data->pos, path[j].co);
701 float strand_t = float(j) / path->segments;
702 if (particle) {
703 float weight = particle_key_weight(particle, i, strand_t);
704 /* NaN or unclamped become 1.0f */
705 seg_data->selection = (weight < 1.0f) ? weight : 1.0f;
706 }
707 else {
708 /* Computed in psys_cache_edit_paths_iter(). */
709 seg_data->selection = path[j].col[0];
710 }
711 GPU_indexbuf_add_generic_vert(elb, curr_point);
712 curr_point++;
713 }
714 /* Finish the segment and add restart primitive. */
716 }
717 return curr_point;
718}
719
721 const int start_index,
722 const int num_path_keys,
723 const int res,
725{
726 int curr_point = start_index;
727 for (int i = 0; i < num_path_keys; i++) {
728 ParticleCacheKey *path = path_cache[i];
729 if (path->segments <= 0) {
730 continue;
731 }
732 for (int k = 0; k < res; k++) {
733 GPU_indexbuf_add_generic_vert(elb, curr_point++);
734 }
736 }
737 return curr_point;
738}
739
742 ParticleCacheKey **path_cache,
743 const ParticleSource particle_source,
744 const int start_index,
745 const int num_path_keys,
746 GPUVertBufRaw *data_step,
747 GPUVertBufRaw *seg_step,
748 float (***r_parent_uvs)[2],
749 GPUVertBufRaw *uv_step,
750 const MTFace **mtfaces,
751 int num_uv_layers,
752 MCol ***r_parent_mcol,
753 GPUVertBufRaw *col_step,
754 const MCol **mcols,
755 int num_col_layers)
756{
757 const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
758 const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
759 if (is_simple && *r_parent_uvs == nullptr) {
760 /* TODO(sergey): For edit mode it should be edit->totcached. */
761 *r_parent_uvs = static_cast<float(**)[2]>(
762 MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs"));
763 }
764 if (is_simple && *r_parent_mcol == nullptr) {
765 *r_parent_mcol = static_cast<MCol **>(
766 MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol"));
767 }
768 int curr_point = start_index;
769 for (int i = 0; i < num_path_keys; i++) {
770 ParticleCacheKey *path = path_cache[i];
771 if (path->segments <= 0) {
772 continue;
773 }
774
775 *(uint *)GPU_vertbuf_raw_step(data_step) = curr_point;
776 *(ushort *)GPU_vertbuf_raw_step(seg_step) = path->segments;
777 curr_point += path->segments + 1;
778
779 if (psmd != nullptr) {
780 float(*uv)[2] = nullptr;
781 MCol *mcol = nullptr;
782
784 psmd,
785 is_simple,
786 num_uv_layers,
787 is_child ? psys->child[i].parent : i,
788 is_child ? i : -1,
789 mtfaces,
790 *r_parent_uvs,
791 &uv);
792
794 psmd,
795 is_simple,
796 num_col_layers,
797 is_child ? psys->child[i].parent : i,
798 is_child ? i : -1,
799 mcols,
800 *r_parent_mcol,
801 &mcol);
802
803 for (int k = 0; k < num_uv_layers; k++) {
804 float *t_uv = (float *)GPU_vertbuf_raw_step(uv_step + k);
805 copy_v2_v2(t_uv, uv[k]);
806 }
807 for (int k = 0; k < num_col_layers; k++) {
808 ushort *scol = (ushort *)GPU_vertbuf_raw_step(col_step + k);
809 particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] :
810 &mcol[k],
811 scol);
812 }
813 if (!is_simple) {
814 MEM_freeN(uv);
815 MEM_freeN(mcol);
816 }
817 }
818 }
819 return curr_point;
820}
821
823 int subdiv)
824{
825 /* Same format as proc_point_buf. */
826 GPUVertFormat format = {0};
828
829 /* Transform feedback buffer only needs to be resident in device memory. */
833
834 /* Create a destination buffer for the transform feedback. Sized appropriately */
835 /* Those are points! not line segments. */
836 uint point_len = cache->final[subdiv].strands_res * cache->strands_len;
837 /* Avoid creating null sized VBO which can lead to crashes on certain platforms. */
838 point_len = max_ii(1, point_len);
839
840 GPU_vertbuf_data_alloc(*cache->final[subdiv].proc_buf, point_len);
841}
842
844 ParticleSystem *psys,
845 ModifierData *md,
846 ParticleHairCache *cache)
847{
848 int active_uv = 0;
849 int render_uv = 0;
850 int active_col = 0;
851 int render_col = 0;
852
854
855 if (psmd != nullptr && psmd->mesh_final != nullptr) {
861 }
865 if (psmd->mesh_final->active_color_attribute != nullptr) {
869 }
870 if (psmd->mesh_final->default_color_attribute != nullptr) {
874 }
875 }
876 }
877
878 GPUVertBufRaw data_step, seg_step;
879 GPUVertBufRaw uv_step[MAX_MTFACE];
880 GPUVertBufRaw *col_step = BLI_array_alloca(col_step, cache->num_col_layers);
881
882 const MTFace *mtfaces[MAX_MTFACE] = {nullptr};
883 const MCol **mcols = BLI_array_alloca(mcols, cache->num_col_layers);
884 float(**parent_uvs)[2] = nullptr;
885 MCol **parent_mcol = nullptr;
886
887 GPUVertFormat format_data = {0};
888 uint data_id = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
889
890 GPUVertFormat format_seg = {0};
891 uint seg_id = GPU_vertformat_attr_add(&format_seg, "data", GPU_COMP_U16, 1, GPU_FETCH_INT);
892
893 GPUVertFormat format_uv = {0};
894 uint uv_id = GPU_vertformat_attr_add(&format_uv, "uv", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
895
896 GPUVertFormat format_col = {0};
898 &format_col, "col", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
899
900 memset(cache->uv_layer_names, 0, sizeof(cache->uv_layer_names));
901
902 /* Strand Data */
906 GPU_vertbuf_attr_get_raw_data(cache->proc_strand_buf, data_id, &data_step);
907
911 GPU_vertbuf_attr_get_raw_data(cache->proc_strand_seg_buf, seg_id, &seg_step);
912
913 /* UV layers */
914 for (int i = 0; i < cache->num_uv_layers; i++) {
918 GPU_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]);
919
920 char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
921 const char *name = CustomData_get_layer_name(
924
925 int n = 0;
926 SNPRINTF(cache->uv_layer_names[i][n], "a%s", attr_safe_name);
927 n++;
928
929 if (i == active_uv) {
930 STRNCPY(cache->uv_layer_names[i][n], "au");
931 n++;
932 }
933 if (i == render_uv) {
934 STRNCPY(cache->uv_layer_names[i][n], "a");
935 n++;
936 }
937 }
938
940 MEM_SAFE_FREE(cache->col_tex);
942
943 cache->proc_col_buf = static_cast<gpu::VertBuf **>(
944 MEM_calloc_arrayN(cache->num_col_layers, sizeof(void *), "proc_col_buf"));
945 cache->col_tex = static_cast<GPUTexture **>(
946 MEM_calloc_arrayN(cache->num_col_layers, sizeof(void *), "col_tex"));
947 cache->col_layer_names = static_cast<char(*)[4][14]>(MEM_calloc_arrayN(
948 cache->num_col_layers, sizeof(*cache->col_layer_names), "col_layer_names"));
949
950 /* Vertex colors */
951 for (int i = 0; i < cache->num_col_layers; i++) {
955 GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]);
956
957 char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
958 const char *name = CustomData_get_layer_name(
961
962 int n = 0;
963 SNPRINTF(cache->col_layer_names[i][n], "a%s", attr_safe_name);
964 n++;
965
966 if (i == active_col) {
967 STRNCPY(cache->col_layer_names[i][n], "ac");
968 n++;
969 }
970 if (i == render_col) {
971 STRNCPY(cache->col_layer_names[i][n], "c");
972 n++;
973 }
974 }
975
976 if (cache->num_uv_layers || cache->num_col_layers) {
977 BKE_mesh_tessface_ensure(psmd->mesh_final);
978 if (cache->num_uv_layers) {
979 for (int j = 0; j < cache->num_uv_layers; j++) {
980 mtfaces[j] = (const MTFace *)CustomData_get_layer_n(
981 &psmd->mesh_final->fdata_legacy, CD_MTFACE, j);
982 }
983 }
984 if (cache->num_col_layers) {
985 for (int j = 0; j < cache->num_col_layers; j++) {
986 mcols[j] = (const MCol *)CustomData_get_layer_n(
987 &psmd->mesh_final->fdata_legacy, CD_MCOL, j);
988 }
989 }
990 }
991
992 if (edit != nullptr && edit->pathcache != nullptr) {
993 particle_batch_cache_fill_strands_data(psys,
994 psmd,
995 edit->pathcache,
996 PARTICLE_SOURCE_PARENT,
997 0,
998 edit->totcached,
999 &data_step,
1000 &seg_step,
1001 &parent_uvs,
1002 uv_step,
1003 mtfaces,
1004 cache->num_uv_layers,
1005 &parent_mcol,
1006 col_step,
1007 mcols,
1008 cache->num_col_layers);
1009 }
1010 else {
1011 int curr_point = 0;
1012 if ((psys->pathcache != nullptr) &&
1013 (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
1014 {
1015 curr_point = particle_batch_cache_fill_strands_data(psys,
1016 psmd,
1017 psys->pathcache,
1018 PARTICLE_SOURCE_PARENT,
1019 0,
1020 psys->totpart,
1021 &data_step,
1022 &seg_step,
1023 &parent_uvs,
1024 uv_step,
1025 mtfaces,
1026 cache->num_uv_layers,
1027 &parent_mcol,
1028 col_step,
1029 mcols,
1030 cache->num_col_layers);
1031 }
1032 if (psys->childcache) {
1033 const int child_count = psys->totchild * psys->part->disp / 100;
1034 curr_point = particle_batch_cache_fill_strands_data(psys,
1035 psmd,
1036 psys->childcache,
1037 PARTICLE_SOURCE_CHILDREN,
1038 curr_point,
1039 child_count,
1040 &data_step,
1041 &seg_step,
1042 &parent_uvs,
1043 uv_step,
1044 mtfaces,
1045 cache->num_uv_layers,
1046 &parent_mcol,
1047 col_step,
1048 mcols,
1049 cache->num_col_layers);
1050 }
1051 }
1052 /* Cleanup. */
1053 if (parent_uvs != nullptr) {
1054 /* TODO(sergey): For edit mode it should be edit->totcached. */
1055 for (int i = 0; i < psys->totpart; i++) {
1056 MEM_SAFE_FREE(parent_uvs[i]);
1057 }
1058 MEM_freeN(parent_uvs);
1059 }
1060 if (parent_mcol != nullptr) {
1061 for (int i = 0; i < psys->totpart; i++) {
1062 MEM_SAFE_FREE(parent_mcol[i]);
1063 }
1064 MEM_freeN(parent_mcol);
1065 }
1066
1067 for (int i = 0; i < cache->num_uv_layers; i++) {
1068 GPU_vertbuf_use(cache->proc_uv_buf[i]);
1069 cache->uv_tex[i] = GPU_texture_create_from_vertbuf("part_uv", cache->proc_uv_buf[i]);
1070 }
1071 for (int i = 0; i < cache->num_col_layers; i++) {
1072 GPU_vertbuf_use(cache->proc_col_buf[i]);
1073 cache->col_tex[i] = GPU_texture_create_from_vertbuf("part_col", cache->proc_col_buf[i]);
1074 }
1075}
1076
1078 ParticleSystem *psys,
1079 ParticleHairCache *cache,
1080 int thickness_res,
1081 int subdiv)
1082{
1083 BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
1084
1085 if (cache->final[subdiv].proc_hairs[thickness_res - 1] != nullptr) {
1086 return;
1087 }
1088
1089 int verts_per_hair = cache->final[subdiv].strands_res * thickness_res;
1090 /* +1 for primitive restart */
1091 int element_count = (verts_per_hair + 1) * cache->strands_len;
1092 GPUPrimType prim_type = (thickness_res == 1) ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP;
1093
1094 static GPUVertFormat format = {0};
1096
1097 /* NOTE: initialize vertex format. Using GPU_COMP_U32 to satisfy Metal's 4-byte minimum
1098 * stride requirement. */
1100
1102 GPU_vertbuf_data_alloc(*vbo, 1);
1103
1105 GPU_indexbuf_init_ex(&elb, prim_type, element_count, element_count);
1106
1107 if (edit != nullptr && edit->pathcache != nullptr) {
1109 edit->pathcache, 0, edit->totcached, verts_per_hair, &elb);
1110 }
1111 else {
1112 int curr_point = 0;
1113 if ((psys->pathcache != nullptr) &&
1114 (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
1115 {
1117 psys->pathcache, 0, psys->totpart, verts_per_hair, &elb);
1118 }
1119 if (psys->childcache) {
1120 const int child_count = psys->totchild * psys->part->disp / 100;
1122 psys->childcache, curr_point, child_count, verts_per_hair, &elb);
1123 }
1124 }
1125
1126 cache->final[subdiv].proc_hairs[thickness_res - 1] = GPU_batch_create_ex(
1128}
1129
1131 ParticleSystem *psys,
1132 ParticleHairCache *cache,
1133 GPUMaterial * /*gpu_material*/)
1134{
1135 if (cache->proc_point_buf == nullptr) {
1136 /* initialize vertex format */
1137 GPUVertFormat pos_format = {0};
1139 &pos_format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1140
1144
1145 GPUVertBufRaw pos_step;
1146 GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step);
1147
1148 GPUVertFormat length_format = {0};
1149 uint length_id = GPU_vertformat_attr_add(
1150 &length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
1151
1155
1156 GPUVertBufRaw length_step;
1157 GPU_vertbuf_attr_get_raw_data(cache->proc_length_buf, length_id, &length_step);
1158
1159 if (edit != nullptr && edit->pathcache != nullptr) {
1161 edit->pathcache, edit->totcached, &pos_step, &length_step);
1162 }
1163 else {
1164 if ((psys->pathcache != nullptr) &&
1165 (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
1166 {
1168 psys->pathcache, psys->totpart, &pos_step, &length_step);
1169 }
1170 if (psys->childcache) {
1171 const int child_count = psys->totchild * psys->part->disp / 100;
1173 psys->childcache, child_count, &pos_step, &length_step);
1174 }
1175 }
1176 }
1177}
1178
1180 ParticleSystem *psys,
1181 ModifierData *md,
1182 ParticleHairCache *hair_cache)
1183{
1184 if (hair_cache->pos != nullptr && hair_cache->indices != nullptr) {
1185 return;
1186 }
1187
1188 int curr_point = 0;
1190
1191 GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
1193
1194 static GPUVertFormat format = {0};
1196 uint *uv_id = nullptr;
1197 uint *col_id = nullptr;
1198 int num_uv_layers = 0;
1199 int num_col_layers = 0;
1200 int active_uv = 0;
1201 int active_col = 0;
1202 const MTFace **mtfaces = nullptr;
1203 const MCol **mcols = nullptr;
1204 float(**parent_uvs)[2] = nullptr;
1205 MCol **parent_mcol = nullptr;
1206
1207 if (psmd != nullptr) {
1211 }
1213 num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->corner_data,
1215 if (psmd->mesh_final->active_color_attribute != nullptr) {
1219 }
1220 }
1221 }
1222
1224
1225 /* initialize vertex format */
1229
1230 if (psmd) {
1231 uv_id = static_cast<uint *>(MEM_mallocN(sizeof(*uv_id) * num_uv_layers, "UV attr format"));
1232 col_id = static_cast<uint *>(MEM_mallocN(sizeof(*col_id) * num_col_layers, "Col attr format"));
1233
1234 for (int i = 0; i < num_uv_layers; i++) {
1235
1236 char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
1237 const char *name = CustomData_get_layer_name(
1240
1241 SNPRINTF(uuid, "a%s", attr_safe_name);
1243
1244 if (i == active_uv) {
1246 }
1247 }
1248
1249 for (int i = 0; i < num_col_layers; i++) {
1250 char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
1251 const char *name = CustomData_get_layer_name(
1254
1255 SNPRINTF(uuid, "a%s", attr_safe_name);
1257
1258 if (i == active_col) {
1260 }
1261 }
1262 }
1263
1265 GPU_vertbuf_data_alloc(*hair_cache->pos, hair_cache->point_len);
1266
1268 GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len);
1269
1270 if (num_uv_layers || num_col_layers) {
1272 if (num_uv_layers) {
1273 mtfaces = static_cast<const MTFace **>(
1274 MEM_mallocN(sizeof(*mtfaces) * num_uv_layers, "Faces UV layers"));
1275 for (int i = 0; i < num_uv_layers; i++) {
1276 mtfaces[i] = (const MTFace *)CustomData_get_layer_n(
1277 &psmd->mesh_final->fdata_legacy, CD_MTFACE, i);
1278 }
1279 }
1280 if (num_col_layers) {
1281 mcols = static_cast<const MCol **>(
1282 MEM_mallocN(sizeof(*mcols) * num_col_layers, "Color layers"));
1283 for (int i = 0; i < num_col_layers; i++) {
1284 mcols[i] = (const MCol *)CustomData_get_layer_n(
1285 &psmd->mesh_final->fdata_legacy, CD_MCOL, i);
1286 }
1287 }
1288 }
1289
1290 if (edit != nullptr && edit->pathcache != nullptr) {
1291 curr_point = particle_batch_cache_fill_segments(psys,
1292 psmd,
1293 edit->pathcache,
1295 0,
1296 0,
1297 edit->totcached,
1298 num_uv_layers,
1299 num_col_layers,
1300 mtfaces,
1301 mcols,
1302 uv_id,
1303 col_id,
1304 &parent_uvs,
1305 &parent_mcol,
1306 &elb,
1307 &attr_id,
1308 hair_cache);
1309 }
1310 else {
1311 if ((psys->pathcache != nullptr) &&
1312 (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
1313 {
1314 curr_point = particle_batch_cache_fill_segments(psys,
1315 psmd,
1316 psys->pathcache,
1318 0,
1319 0,
1320 psys->totpart,
1321 num_uv_layers,
1322 num_col_layers,
1323 mtfaces,
1324 mcols,
1325 uv_id,
1326 col_id,
1327 &parent_uvs,
1328 &parent_mcol,
1329 &elb,
1330 &attr_id,
1331 hair_cache);
1332 }
1333 if (psys->childcache != nullptr) {
1334 const int child_count = psys->totchild * psys->part->disp / 100;
1335 curr_point = particle_batch_cache_fill_segments(psys,
1336 psmd,
1337 psys->childcache,
1339 psys->totpart,
1340 curr_point,
1341 child_count,
1342 num_uv_layers,
1343 num_col_layers,
1344 mtfaces,
1345 mcols,
1346 uv_id,
1347 col_id,
1348 &parent_uvs,
1349 &parent_mcol,
1350 &elb,
1351 &attr_id,
1352 hair_cache);
1353 }
1354 }
1355 /* Cleanup. */
1356 if (parent_uvs != nullptr) {
1357 /* TODO(sergey): For edit mode it should be edit->totcached. */
1358 for (int i = 0; i < psys->totpart; i++) {
1359 MEM_SAFE_FREE(parent_uvs[i]);
1360 }
1361 MEM_freeN(parent_uvs);
1362 }
1363 if (parent_mcol != nullptr) {
1364 for (int i = 0; i < psys->totpart; i++) {
1365 MEM_SAFE_FREE(parent_mcol[i]);
1366 }
1367 MEM_freeN(parent_mcol);
1368 }
1369 if (num_uv_layers) {
1370 MEM_freeN((void *)mtfaces);
1371 }
1372 if (num_col_layers) {
1373 MEM_freeN((void *)mcols);
1374 }
1375 if (psmd != nullptr) {
1376 MEM_freeN(uv_id);
1377 }
1378 hair_cache->indices = GPU_indexbuf_build(&elb);
1379}
1380
1382 ParticleSystem *psys,
1383 ParticlePointCache *point_cache)
1384{
1385 if (point_cache->pos != nullptr) {
1386 return;
1387 }
1388
1389 static GPUVertFormat format = {0};
1390 static uint pos_id, rot_id, val_id;
1391 int i, curr_point;
1392 ParticleData *pa;
1394 ParticleSimulationData sim = {nullptr};
1395 const DRWContextState *draw_ctx = DRW_context_state_get();
1396
1397 sim.depsgraph = draw_ctx->depsgraph;
1398 sim.scene = draw_ctx->scene;
1399 sim.ob = object;
1400 sim.psys = psys;
1401 sim.psmd = psys_get_modifier(object, psys);
1402 psys_sim_data_init(&sim);
1403
1404 GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
1405
1406 if (format.attr_len == 0) {
1407 /* initialize vertex format */
1408 pos_id = GPU_vertformat_attr_add(&format, "part_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1409 val_id = GPU_vertformat_attr_add(&format, "part_val", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
1410 rot_id = GPU_vertformat_attr_add(&format, "part_rot", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1411 }
1412
1414 GPU_vertbuf_data_alloc(*point_cache->pos, psys->totpart);
1415
1416 for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
1417 state.time = DEG_get_ctime(draw_ctx->depsgraph);
1418 if (!psys_get_particle_state(&sim, i, &state, false)) {
1419 continue;
1420 }
1421
1422 float val;
1423
1424 GPU_vertbuf_attr_set(point_cache->pos, pos_id, curr_point, state.co);
1425 GPU_vertbuf_attr_set(point_cache->pos, rot_id, curr_point, state.rot);
1426
1427 switch (psys->part->draw_col) {
1428 case PART_DRAW_COL_VEL:
1429 val = len_v3(state.vel) / psys->part->color_vec_max;
1430 break;
1431 case PART_DRAW_COL_ACC:
1432 val = len_v3v3(state.vel, pa->prev_state.vel) /
1433 ((state.time - pa->prev_state.time) * psys->part->color_vec_max);
1434 break;
1435 default:
1436 val = -1.0f;
1437 break;
1438 }
1439
1440 GPU_vertbuf_attr_set(point_cache->pos, val_id, curr_point, &val);
1441
1442 curr_point++;
1443 }
1444
1445 if (curr_point != psys->totpart) {
1446 GPU_vertbuf_data_resize(*point_cache->pos, curr_point);
1447 }
1448
1449 psys_sim_data_free(&sim);
1450}
1451
1453 ParticleSystem *psys,
1454 PTCacheEdit *edit)
1455{
1456 if (edit->psys == nullptr) {
1457 return;
1458 }
1459 /* NOTE: Get flag from particle system coming from drawing object.
1460 * this is where depsgraph will be setting flags to.
1461 */
1462 const DRWContextState *draw_ctx = DRW_context_state_get();
1463 Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
1464 Object *object_orig = DEG_get_original_object(object_eval);
1465 if (psys->flag & PSYS_HAIR_UPDATED) {
1466 PE_update_object(draw_ctx->depsgraph, scene_orig, object_orig, 0);
1467 psys->flag &= ~PSYS_HAIR_UPDATED;
1468 }
1469 if (edit->pathcache == nullptr) {
1470 Depsgraph *depsgraph = draw_ctx->depsgraph;
1472 scene_orig,
1473 object_orig,
1474 edit,
1477 }
1478}
1479
1480static void drw_particle_update_ptcache(Object *object_eval, ParticleSystem *psys)
1481{
1482 if ((object_eval->mode & OB_MODE_PARTICLE_EDIT) == 0) {
1483 return;
1484 }
1485 const DRWContextState *draw_ctx = DRW_context_state_get();
1486 Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
1487 Object *object_orig = DEG_get_original_object(object_eval);
1488 PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, object_orig);
1489 if (edit != nullptr) {
1490 drw_particle_update_ptcache_edit(object_eval, psys, edit);
1491 }
1492}
1493
1500
1502 ParticleSystem *psys,
1503 ModifierData *md,
1504 PTCacheEdit *edit,
1505 ParticleDrawSource *r_draw_source)
1506{
1507 const DRWContextState *draw_ctx = DRW_context_state_get();
1508 r_draw_source->object = object;
1509 r_draw_source->psys = psys;
1510 r_draw_source->md = md;
1511 r_draw_source->edit = edit;
1512 if (psys_in_edit_mode(draw_ctx->depsgraph, psys)) {
1513 r_draw_source->object = DEG_get_original_object(object);
1514 r_draw_source->psys = psys_orig_get(psys);
1515 }
1516}
1517
1519 ParticleSystem *psys,
1520 ModifierData *md)
1521{
1523 if (cache->hair.hairs == nullptr) {
1524 drw_particle_update_ptcache(object, psys);
1525 ParticleDrawSource source;
1526 drw_particle_get_hair_source(object, psys, md, nullptr, &source);
1527 ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
1528 particle_batch_cache_ensure_pos_and_seg(source.edit, source.psys, source.md, &cache->hair);
1529 cache->hair.hairs = GPU_batch_create(
1530 GPU_PRIM_LINE_STRIP, cache->hair.pos, cache->hair.indices);
1531 }
1532 return cache->hair.hairs;
1533}
1534
1536{
1538
1539 if (cache->point.points == nullptr) {
1540 particle_batch_cache_ensure_pos(object, psys, &cache->point);
1541 cache->point.points = GPU_batch_create(GPU_PRIM_POINTS, cache->point.pos, nullptr);
1542 }
1543
1544 return cache->point.points;
1545}
1546
1548 ParticleSystem *psys,
1549 ModifierData * /*md*/,
1550 ParticleHairCache *hair_cache,
1551 bool use_weight)
1552{
1553 if (hair_cache->pos != nullptr && hair_cache->indices != nullptr) {
1554 return;
1555 }
1556
1557 ParticleData *particle = (use_weight) ? psys->particles : nullptr;
1558
1559 GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
1561
1562 GPUVertBufRaw data_step;
1564 uint pos_id, selection_id;
1565 GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &selection_id);
1566
1567 hair_cache->pos = GPU_vertbuf_create_with_format(*edit_point_format);
1568 GPU_vertbuf_data_alloc(*hair_cache->pos, hair_cache->point_len);
1569 GPU_vertbuf_attr_get_raw_data(hair_cache->pos, pos_id, &data_step);
1570
1571 GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len);
1572
1573 if (edit != nullptr && edit->pathcache != nullptr) {
1575 edit, particle, edit->pathcache, 0, edit->totcached, &elb, &data_step);
1576 }
1577 hair_cache->indices = GPU_indexbuf_build(&elb);
1578}
1579
1581 ParticleSystem *psys,
1582 PTCacheEdit *edit,
1583 bool use_weight)
1584{
1586 if (cache->edit_is_weight != use_weight) {
1589 }
1590 if (cache->edit_hair.hairs != nullptr) {
1591 return cache->edit_hair.hairs;
1592 }
1593 drw_particle_update_ptcache_edit(object, psys, edit);
1594 ensure_seg_pt_count(edit, psys, &cache->edit_hair);
1595 particle_batch_cache_ensure_edit_pos_and_seg(edit, psys, nullptr, &cache->edit_hair, use_weight);
1598 cache->edit_is_weight = use_weight;
1599 return cache->edit_hair.hairs;
1600}
1601
1603{
1604 if (cache->edit_inner_pos != nullptr) {
1605 return;
1606 }
1607 cache->edit_inner_point_len = 0;
1608 for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1609 const PTCacheEditPoint *point = &edit->points[point_index];
1610 if (point->flag & PEP_HIDE) {
1611 continue;
1612 }
1613 BLI_assert(point->totkey >= 1);
1614 cache->edit_inner_point_len += (point->totkey - 1);
1615 }
1616}
1617
1619 ParticleBatchCache *cache)
1620{
1621 if (cache->edit_inner_pos != nullptr) {
1622 return;
1623 }
1624
1625 uint pos_id, selection_id;
1626 GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &selection_id);
1627
1628 cache->edit_inner_pos = GPU_vertbuf_create_with_format(*edit_point_format);
1630
1631 int global_key_index = 0;
1632 for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1633 const PTCacheEditPoint *point = &edit->points[point_index];
1634 if (point->flag & PEP_HIDE) {
1635 continue;
1636 }
1637 for (int key_index = 0; key_index < point->totkey - 1; key_index++) {
1638 PTCacheEditKey *key = &point->keys[key_index];
1639 float selection = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
1640 GPU_vertbuf_attr_set(cache->edit_inner_pos, pos_id, global_key_index, key->world_co);
1641 GPU_vertbuf_attr_set(cache->edit_inner_pos, selection_id, global_key_index, &selection);
1642 global_key_index++;
1643 }
1644 }
1645}
1646
1648 ParticleSystem *psys,
1649 PTCacheEdit *edit)
1650{
1652 if (cache->edit_inner_points != nullptr) {
1653 return cache->edit_inner_points;
1654 }
1655 drw_particle_update_ptcache_edit(object, psys, edit);
1656 ensure_edit_inner_points_count(edit, cache);
1659 return cache->edit_inner_points;
1660}
1661
1663{
1664 if (cache->edit_tip_pos != nullptr) {
1665 return;
1666 }
1667 cache->edit_tip_point_len = 0;
1668 for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1669 const PTCacheEditPoint *point = &edit->points[point_index];
1670 if (point->flag & PEP_HIDE) {
1671 continue;
1672 }
1673 cache->edit_tip_point_len += 1;
1674 }
1675}
1676
1678{
1679 if (cache->edit_tip_pos != nullptr) {
1680 return;
1681 }
1682
1683 uint pos_id, selection_id;
1684 GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &selection_id);
1685
1686 cache->edit_tip_pos = GPU_vertbuf_create_with_format(*edit_point_format);
1688
1689 int global_point_index = 0;
1690 for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1691 const PTCacheEditPoint *point = &edit->points[point_index];
1692 if (point->flag & PEP_HIDE) {
1693 continue;
1694 }
1695 PTCacheEditKey *key = &point->keys[point->totkey - 1];
1696 float selection = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
1697
1698 GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, global_point_index, key->world_co);
1699 GPU_vertbuf_attr_set(cache->edit_tip_pos, selection_id, global_point_index, &selection);
1700 global_point_index++;
1701 }
1702}
1703
1705 ParticleSystem *psys,
1706 PTCacheEdit *edit)
1707{
1709 if (cache->edit_tip_points != nullptr) {
1710 return cache->edit_tip_points;
1711 }
1712 drw_particle_update_ptcache_edit(object, psys, edit);
1713 ensure_edit_tip_points_count(edit, cache);
1716 return cache->edit_tip_points;
1717}
1718
1720 ParticleSystem *psys,
1721 ModifierData *md,
1722 ParticleHairCache **r_hair_cache,
1723 GPUMaterial *gpu_material,
1724 int subdiv,
1725 int thickness_res)
1726{
1727 bool need_ft_update = false;
1728
1729 drw_particle_update_ptcache(object, psys);
1730
1731 ParticleDrawSource source;
1732 drw_particle_get_hair_source(object, psys, md, nullptr, &source);
1733
1734 ParticleSettings *part = source.psys->part;
1736 *r_hair_cache = &cache->hair;
1737
1738 (*r_hair_cache)->final[subdiv].strands_res = 1 << (part->draw_step + subdiv);
1739
1740 /* Refreshed on combing and simulation. */
1741 if ((*r_hair_cache)->proc_point_buf == nullptr ||
1742 (gpu_material && (*r_hair_cache)->proc_length_buf == nullptr))
1743 {
1744 ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
1746 source.edit, source.psys, &cache->hair, gpu_material);
1747 need_ft_update = true;
1748 }
1749
1750 /* Refreshed if active layer or custom data changes. */
1751 if ((*r_hair_cache)->proc_strand_buf == nullptr) {
1753 source.edit, source.psys, source.md, &cache->hair);
1754 }
1755
1756 /* Refreshed only on subdiv count change. */
1757 if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) {
1759 need_ft_update = true;
1760 }
1761 if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) {
1763 source.edit, source.psys, &cache->hair, thickness_res, subdiv);
1764 }
1765
1766 return need_ft_update;
1767}
1768
1769} // namespace blender::draw
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer_n(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_named_layer(const CustomData *data, eCustomDataType type, blender::StringRef name)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
int CustomData_get_render_layer(const CustomData *data, eCustomDataType type)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
void BKE_mesh_tessface_ensure(Mesh *mesh)
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition particle.cc:2150
#define DMCACHE_NOTFOUND
struct ParticleSystem * psys_orig_get(struct ParticleSystem *psys)
Definition particle.cc:656
void psys_cache_edit_paths(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, bool use_render_params)
Definition particle.cc:3662
void psys_interpolate_uvs(const struct MTFace *tface, int quad, const float w[4], float uvco[2])
bool psys_in_edit_mode(struct Depsgraph *depsgraph, const struct ParticleSystem *psys)
@ BKE_PARTICLE_BATCH_DIRTY_ALL
void psys_sim_data_free(struct ParticleSimulationData *sim)
Definition particle.cc:629
#define DMCACHE_ISCHILD
void psys_interpolate_mcol(const struct MCol *mcol, int quad, const float w[4], struct MCol *mc)
void psys_sim_data_init(struct ParticleSimulationData *sim)
Definition particle.cc:588
bool psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, bool always)
Definition particle.cc:4886
#define PEP_HIDE
#define PEK_SELECT
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:25
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE int max_ii(int a, int b)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned short ushort
unsigned int uint
#define UNLIKELY(x)
#define ELEM(...)
@ DAG_EVAL_RENDER
float DEG_get_ctime(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
ID * DEG_get_original_id(ID *id)
Object * DEG_get_original_object(Object *object)
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT2
#define MAX_MTFACE
@ OB_MODE_PARTICLE_EDIT
@ PART_CHILD_PARTICLES
@ PART_FROM_VOLUME
@ PART_FROM_FACE
@ PART_DRAW_COL_ACC
@ PART_DRAW_COL_VEL
@ PART_DRAW_PARENT
struct ParticleSystem ParticleSystem
@ PSYS_HAIR_UPDATED
#define DRW_TEXTURE_FREE_SAFE(tex)
void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
PTCacheEdit * PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:56
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:149
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:205
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:51
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
bool GPU_transform_feedback_support()
#define GPU_INDEXBUF_DISCARD_SAFE(elem)
void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *)
blender::gpu::IndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *, uint v)
void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uint vertex_len)
GPUPrimType
@ GPU_PRIM_POINTS
@ GPU_PRIM_LINE_STRIP
@ GPU_PRIM_TRI_STRIP
GPUTexture * GPU_texture_create_from_vertbuf(const char *name, blender::gpu::VertBuf *vertex_buf)
void GPU_vertbuf_attr_get_raw_data(blender::gpu::VertBuf *, uint a_idx, GPUVertBufRaw *access)
GPU_INLINE void * GPU_vertbuf_raw_step(GPUVertBufRaw *a)
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_use(blender::gpu::VertBuf *)
void GPU_vertbuf_data_resize(blender::gpu::VertBuf &verts, uint v_len)
blender::gpu::VertBuf * GPU_vertbuf_create_with_format_ex(const GPUVertFormat &format, GPUUsageType usage)
void GPU_vertbuf_attr_set(blender::gpu::VertBuf *, uint a_idx, uint v_idx, const void *data)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_USAGE_STATIC
@ GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY
@ GPU_USAGE_DEVICE_ONLY
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
#define GPU_MAX_SAFE_ATTR_NAME
void GPU_vertformat_clear(GPUVertFormat *)
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias)
@ GPU_COMP_U16
@ GPU_COMP_F32
@ GPU_COMP_I32
@ GPU_COMP_U32
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
BPy_StructRNA * depsgraph
#define floorf(x)
#define MAX_THICKRES
#define MAX_HAIR_SUBDIV
const DRWContextState * DRW_context_state_get()
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
struct @157336070235062372277311340362362342103123126032::@132215023242101136103363133227133264017254024241 attr_id
format
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define unit_float_to_ushort_clamp(val)
float BLI_color_from_srgb_table[256]
ccl_device_inline float2 interp(const float2 a, const float2 b, float t)
static ulong state[N]
static void drw_particle_update_ptcache(Object *object_eval, ParticleSystem *psys)
static void count_cache_segment_keys(ParticleCacheKey **pathcache, const int num_path_cache_keys, ParticleHairCache *hair_cache)
void DRW_particle_batch_cache_free(ParticleSystem *psys)
static int particle_batch_cache_fill_strands_data(ParticleSystem *psys, ParticleSystemModifierData *psmd, ParticleCacheKey **path_cache, const ParticleSource particle_source, const int start_index, const int num_path_keys, GPUVertBufRaw *data_step, GPUVertBufRaw *seg_step, float(***r_parent_uvs)[2], GPUVertBufRaw *uv_step, const MTFace **mtfaces, int num_uv_layers, MCol ***r_parent_mcol, GPUVertBufRaw *col_step, const MCol **mcols, int num_col_layers)
blender::gpu::Batch * DRW_particles_batch_cache_get_edit_inner_points(Object *object, ParticleSystem *psys, PTCacheEdit *edit)
blender::gpu::Batch * DRW_particles_batch_cache_get_edit_tip_points(Object *object, ParticleSystem *psys, PTCacheEdit *edit)
static void drw_particle_update_ptcache_edit(Object *object_eval, ParticleSystem *psys, PTCacheEdit *edit)
static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *cache, GPUMaterial *)
static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit, ParticleSystem *psys, ModifierData *md, ParticleHairCache *hair_cache)
static int particle_batch_cache_fill_segments_edit(const PTCacheEdit *, const ParticleData *particle, ParticleCacheKey **path_cache, const int start_index, const int num_path_keys, GPUIndexBufBuilder *elb, GPUVertBufRaw *attr_step)
static bool particle_batch_cache_valid(ParticleSystem *psys)
static GPUVertFormat * edit_points_vert_format_get(uint *r_pos_id, uint *r_selection_id)
static void particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit *edit, ParticleBatchCache *cache)
blender::gpu::Batch * DRW_particles_batch_cache_get_edit_strands(Object *object, ParticleSystem *psys, PTCacheEdit *edit, bool use_weight)
static void particle_batch_cache_ensure_edit_pos_and_seg(PTCacheEdit *edit, ParticleSystem *psys, ModifierData *, ParticleHairCache *hair_cache, bool use_weight)
static void particle_calculate_uvs(ParticleSystem *psys, ParticleSystemModifierData *psmd, const bool is_simple, const int num_uv_layers, const int parent_index, const int child_index, const MTFace **mtfaces, float(**r_parent_uvs)[2], float(**r_uv)[2])
static void ensure_edit_inner_points_count(const PTCacheEdit *edit, ParticleBatchCache *cache)
blender::gpu::Batch * DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *psys)
static void particle_batch_cache_clear(ParticleSystem *psys)
static void particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey **path_cache, const int num_path_keys, GPUVertBufRaw *attr_step, GPUVertBufRaw *length_step)
static void particle_interpolate_children_uvs(ParticleSystem *psys, ParticleSystemModifierData *psmd, const int num_uv_layers, const int child_index, const MTFace **mtfaces, float(*r_uv)[2])
static void particle_pack_mcol(MCol *mcol, ushort r_scol[3])
static void particle_batch_cache_ensure_edit_inner_pos(PTCacheEdit *edit, ParticleBatchCache *cache)
static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit, ParticleSystem *psys, ModifierData *md, ParticleHairCache *cache)
static void drw_particle_get_hair_source(Object *object, ParticleSystem *psys, ModifierData *md, PTCacheEdit *edit, ParticleDrawSource *r_draw_source)
static void particle_batch_cache_clear_point(ParticlePointCache *point_cache)
static void particle_batch_cache_ensure_pos(Object *object, ParticleSystem *psys, ParticlePointCache *point_cache)
static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *cache, int thickness_res, int subdiv)
bool particles_ensure_procedural_data(Object *object, ParticleSystem *psys, ModifierData *md, ParticleHairCache **r_hair_cache, GPUMaterial *gpu_material, int subdiv, int thickness_res)
static float particle_key_weight(const ParticleData *particle, int strand, float t)
static void particle_calculate_parent_mcol(ParticleSystem *psys, ParticleSystemModifierData *psmd, const int num_col_layers, const int parent_index, const MCol **mcols, MCol *r_mcol)
static void particle_calculate_mcol(ParticleSystem *psys, ParticleSystemModifierData *psmd, const bool is_simple, const int num_col_layers, const int parent_index, const int child_index, const MCol **mcols, MCol **r_parent_mcol, MCol **r_mcol)
static void particle_batch_cache_init(ParticleSystem *psys)
void DRW_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode)
static int particle_batch_cache_fill_segments_indices(ParticleCacheKey **path_cache, const int start_index, const int num_path_keys, const int res, GPUIndexBufBuilder *elb)
static ParticleBatchCache * particle_batch_cache_get(ParticleSystem *psys)
static void particle_interpolate_children_mcol(ParticleSystem *psys, ParticleSystemModifierData *psmd, const int num_col_layers, const int child_index, const MCol **mcols, MCol *r_mcol)
static int particle_batch_cache_fill_segments(ParticleSystem *psys, ParticleSystemModifierData *psmd, ParticleCacheKey **path_cache, const ParticleSource particle_source, const int global_offset, const int start_index, const int num_path_keys, const int num_uv_layers, const int num_col_layers, const MTFace **mtfaces, const MCol **mcols, uint *uv_id, uint *col_id, float(***r_parent_uvs)[2], MCol ***r_parent_mcol, GPUIndexBufBuilder *elb, HairAttributeID *attr_id, ParticleHairCache *hair_cache)
blender::gpu::Batch * DRW_particles_batch_cache_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache, int subdiv)
static void ensure_seg_pt_count(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *hair_cache)
static void ensure_edit_tip_points_count(const PTCacheEdit *edit, ParticleBatchCache *cache)
static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
static void particle_calculate_parent_uvs(ParticleSystem *psys, ParticleSystemModifierData *psmd, const int num_uv_layers, const int parent_index, const MTFace **mtfaces, float(*r_uv)[2])
static bool is_child(const Object *ob, const Object *parent)
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]
Depsgraph * depsgraph
unsigned char r
unsigned char g
unsigned char b
unsigned int v4
CustomData corner_data
char * default_color_attribute
CustomData fdata_legacy
int totface_legacy
int faces_num
char * active_color_attribute
struct ParticleCacheKey ** pathcache
PTCacheEditPoint * points
struct ParticleSystem * psys
ParticleKey prev_state
GPUTexture * uv_tex[MAX_MTFACE]
blender::gpu::IndexBuf * indices
blender::gpu::VertBuf ** proc_col_buf
blender::gpu::VertBuf * proc_length_buf
blender::gpu::VertBuf * proc_strand_buf
blender::gpu::VertBuf * proc_uv_buf[MAX_MTFACE]
blender::gpu::VertBuf * proc_strand_seg_buf
char uv_layer_names[MAX_MTFACE][MAX_LAYER_NAME_CT][MAX_LAYER_NAME_LEN]
blender::gpu::Batch * hairs
blender::gpu::VertBuf * proc_point_buf
ParticleHairFinalCache final[MAX_HAIR_SUBDIV]
blender::gpu::VertBuf * pos
char(* col_layer_names)[MAX_LAYER_NAME_CT][MAX_LAYER_NAME_LEN]
blender::gpu::VertBuf * proc_buf
blender::gpu::Batch * proc_hairs[MAX_THICKRES]
struct Depsgraph * depsgraph
struct ParticleSystemModifierData * psmd
struct Scene * scene
struct ParticleSystem * psys
struct Object * ob
struct ParticleSystem * psys
ChildParticle * child
ParticleData * particles
ParticleSettings * part
struct ParticleCacheKey ** childcache
struct ParticleCacheKey ** pathcache