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
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) {
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) {
994 psmd,
995 edit->pathcache,
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 {
1016 psmd,
1017 psys->pathcache,
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;
1035 psmd,
1036 psys->childcache,
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)
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
@ BKE_PARTICLE_BATCH_DIRTY_ALL
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_DRAW_COL_ACC
@ PART_DRAW_COL_VEL
@ PART_FROM_VOLUME
@ PART_FROM_FACE
@ PART_DRAW_PARENT
@ PART_CHILD_PARTICLES
@ 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)
const Depsgraph * 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 @620::@623 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)
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