Blender V4.5
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
12#include "DNA_scene_types.h"
13#include "DRW_render.hh"
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_alloca.h"
18#include "BLI_math_color.h"
19#include "BLI_math_vector.h"
20#include "BLI_string.h"
21#include "BLI_utildefines.h"
22
24#include "DNA_mesh_types.h"
25#include "DNA_meshdata_types.h"
26#include "DNA_modifier_types.h"
27#include "DNA_particle_types.h"
28
29#include "BKE_customdata.hh"
30#include "BKE_mesh.hh"
32#include "BKE_particle.h"
33#include "BKE_pointcache.h"
34
35#include "ED_particle.hh"
36
37#include "GPU_batch.hh"
38#include "GPU_capabilities.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 const GPUVertFormat *edit_points_vert_format_get(uint *r_pos_id, uint *r_selection_id)
100{
101 static uint pos_id, selection_id;
102 static const GPUVertFormat edit_point_format = [&]() {
105 selection_id = GPU_vertformat_attr_add(&format, "selection", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
106 return format;
107 }();
108 *r_pos_id = pos_id;
109 *r_selection_id = selection_id;
110 return &edit_point_format;
111}
112
114{
115 ParticleBatchCache *cache = static_cast<ParticleBatchCache *>(psys->batch_cache);
116
117 if (cache == nullptr) {
118 return false;
119 }
120
121 if (cache->is_dirty == false) {
122 return true;
123 }
124
125 return false;
126
127 return true;
128}
129
131{
132 ParticleBatchCache *cache = static_cast<ParticleBatchCache *>(psys->batch_cache);
133
134 if (!cache) {
135 cache = static_cast<ParticleBatchCache *>(
136 psys->batch_cache = MEM_callocN(sizeof(*cache), __func__));
137 }
138 else {
139 memset(cache, 0, sizeof(*cache));
140 }
141
142 cache->is_dirty = false;
143}
144
146{
147 if (!particle_batch_cache_valid(psys)) {
150 }
151 return static_cast<ParticleBatchCache *>(psys->batch_cache);
152}
153
155{
156 ParticleBatchCache *cache = static_cast<ParticleBatchCache *>(psys->batch_cache);
157 if (cache == nullptr) {
158 return;
159 }
160 switch (mode) {
162 cache->is_dirty = true;
163 break;
164 default:
165 BLI_assert(0);
166 }
167}
168
170{
171 GPU_BATCH_DISCARD_SAFE(point_cache->points);
172 GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
173}
174
176{
177 /* TODO: more granular update tagging. */
180
183
184 for (int i = 0; i < MAX_MTFACE; i++) {
186 GPU_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]);
187 }
188 for (int i = 0; i < hair_cache->num_col_layers; i++) {
190 GPU_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]);
191 }
192
193 for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
195 for (int j = 0; j < MAX_THICKRES; j++) {
196 GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]);
197 }
198 }
199
200 /* "Normal" legacy hairs */
201 GPU_BATCH_DISCARD_SAFE(hair_cache->hairs);
202 GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
204
205 MEM_SAFE_FREE(hair_cache->proc_col_buf);
206 MEM_SAFE_FREE(hair_cache->col_tex);
207 MEM_SAFE_FREE(hair_cache->col_layer_names);
208}
209
211{
212 ParticleBatchCache *cache = static_cast<ParticleBatchCache *>(psys->batch_cache);
213 if (!cache) {
214 return;
215 }
216
217 /* All memory allocated by `cache` must be freed. */
218
220
223
228}
229
235
237 const int num_path_cache_keys,
238 ParticleHairCache *hair_cache)
239{
240 for (int i = 0; i < num_path_cache_keys; i++) {
241 ParticleCacheKey *path = pathcache[i];
242 if (path->segments > 0) {
243 hair_cache->strands_len++;
244 hair_cache->elems_len += path->segments + 2;
245 hair_cache->point_len += path->segments + 1;
246 }
247 }
248}
249
251 ParticleSystem *psys,
252 ParticleHairCache *hair_cache)
253{
254 if ((hair_cache->pos != nullptr && hair_cache->indices != nullptr) ||
255 (hair_cache->proc_point_buf != nullptr))
256 {
257 return;
258 }
259
260 hair_cache->strands_len = 0;
261 hair_cache->elems_len = 0;
262 hair_cache->point_len = 0;
263
264 if (edit != nullptr && edit->pathcache != nullptr) {
265 count_cache_segment_keys(edit->pathcache, edit->totcached, hair_cache);
266 }
267 else {
268 if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
269 count_cache_segment_keys(psys->pathcache, psys->totpart, hair_cache);
270 }
271 if (psys->childcache) {
272 const int child_count = psys->totchild * psys->part->disp / 100;
273 count_cache_segment_keys(psys->childcache, child_count, hair_cache);
274 }
275 }
276}
277
278static void particle_pack_mcol(MCol *mcol, ushort r_scol[3])
279{
280 /* Convert to linear ushort and swizzle */
284}
285
286/* Used by parent particles and simple children. */
289 const int num_uv_layers,
290 const int parent_index,
291 const MTFace **mtfaces,
292 float (*r_uv)[2])
293{
294 if (psmd == nullptr) {
295 return;
296 }
297 const int emit_from = psmd->psys->part->from;
298 if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
299 return;
300 }
301 ParticleData *particle = &psys->particles[parent_index];
302 int num = particle->num_dmcache;
304 if (particle->num < psmd->mesh_final->totface_legacy) {
305 num = particle->num;
306 }
307 }
309 const MFace *mfaces = static_cast<const MFace *>(
311 if (UNLIKELY(mfaces == nullptr)) {
313 "A mesh with polygons should always have a generated 'CD_MFACE' layer!");
314 return;
315 }
316 const MFace *mface = &mfaces[num];
317 for (int j = 0; j < num_uv_layers; j++) {
318 psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]);
319 }
320 }
321}
322
325 const int num_col_layers,
326 const int parent_index,
327 const MCol **mcols,
328 MCol *r_mcol)
329{
330 if (psmd == nullptr) {
331 return;
332 }
333 const int emit_from = psmd->psys->part->from;
334 if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
335 return;
336 }
337 ParticleData *particle = &psys->particles[parent_index];
338 int num = particle->num_dmcache;
340 if (particle->num < psmd->mesh_final->totface_legacy) {
341 num = particle->num;
342 }
343 }
345 const MFace *mfaces = static_cast<const MFace *>(
347 if (UNLIKELY(mfaces == nullptr)) {
349 "A mesh with polygons should always have a generated 'CD_MFACE' layer!");
350 return;
351 }
352 const MFace *mface = &mfaces[num];
353 for (int j = 0; j < num_col_layers; j++) {
354 /* CustomDataLayer CD_MCOL has 4 structs per face. */
355 psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
356 }
357 }
358}
359
360/* Used by interpolated children. */
363 const int num_uv_layers,
364 const int child_index,
365 const MTFace **mtfaces,
366 float (*r_uv)[2])
367{
368 if (psmd == nullptr) {
369 return;
370 }
371 const int emit_from = psmd->psys->part->from;
372 if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
373 return;
374 }
375 ChildParticle *particle = &psys->child[child_index];
376 int num = particle->num;
377 if (num != DMCACHE_NOTFOUND) {
378 const MFace *mfaces = static_cast<const MFace *>(
380 const MFace *mface = &mfaces[num];
381 for (int j = 0; j < num_uv_layers; j++) {
382 psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]);
383 }
384 }
385}
386
389 const int num_col_layers,
390 const int child_index,
391 const MCol **mcols,
392 MCol *r_mcol)
393{
394 if (psmd == nullptr) {
395 return;
396 }
397 const int emit_from = psmd->psys->part->from;
398 if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
399 return;
400 }
401 ChildParticle *particle = &psys->child[child_index];
402 int num = particle->num;
403 if (num != DMCACHE_NOTFOUND) {
404 const MFace *mfaces = static_cast<const MFace *>(
406 const MFace *mface = &mfaces[num];
407 for (int j = 0; j < num_col_layers; j++) {
408 /* CustomDataLayer CD_MCOL has 4 structs per face. */
409 psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
410 }
411 }
412}
413
416 const bool is_simple,
417 const int num_uv_layers,
418 const int parent_index,
419 const int child_index,
420 const MTFace **mtfaces,
421 float (**r_parent_uvs)[2],
422 float (**r_uv)[2])
423{
424 if (psmd == nullptr) {
425 return;
426 }
427 if (is_simple) {
428 if (r_parent_uvs[parent_index] != nullptr) {
429 *r_uv = r_parent_uvs[parent_index];
430 }
431 else {
432 *r_uv = MEM_calloc_arrayN<float[2]>(num_uv_layers, "Particle UVs");
433 }
434 }
435 else {
436 *r_uv = MEM_calloc_arrayN<float[2]>(num_uv_layers, "Particle UVs");
437 }
438 if (child_index == -1) {
439 /* Calculate UVs for parent particles. */
440 if (is_simple) {
441 r_parent_uvs[parent_index] = *r_uv;
442 }
443 particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
444 }
445 else {
446 /* Calculate UVs for child particles. */
447 if (!is_simple) {
448 particle_interpolate_children_uvs(psys, psmd, num_uv_layers, child_index, mtfaces, *r_uv);
449 }
450 else if (!r_parent_uvs[psys->child[child_index].parent]) {
451 r_parent_uvs[psys->child[child_index].parent] = *r_uv;
452 particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
453 }
454 }
455}
456
459 const bool is_simple,
460 const int num_col_layers,
461 const int parent_index,
462 const int child_index,
463 const MCol **mcols,
464 MCol **r_parent_mcol,
465 MCol **r_mcol)
466{
467 if (psmd == nullptr) {
468 return;
469 }
470 if (is_simple) {
471 if (r_parent_mcol[parent_index] != nullptr) {
472 *r_mcol = r_parent_mcol[parent_index];
473 }
474 else {
475 *r_mcol = MEM_calloc_arrayN<MCol>(num_col_layers, "Particle MCol");
476 }
477 }
478 else {
479 *r_mcol = MEM_calloc_arrayN<MCol>(num_col_layers, "Particle MCol");
480 }
481 if (child_index == -1) {
482 /* Calculate MCols for parent particles. */
483 if (is_simple) {
484 r_parent_mcol[parent_index] = *r_mcol;
485 }
486 particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
487 }
488 else {
489 /* Calculate MCols for child particles. */
490 if (!is_simple) {
491 particle_interpolate_children_mcol(psys, psmd, num_col_layers, child_index, mcols, *r_mcol);
492 }
493 else if (!r_parent_mcol[psys->child[child_index].parent]) {
494 r_parent_mcol[psys->child[child_index].parent] = *r_mcol;
495 particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
496 }
497 }
498}
499
500/* Will return last filled index. */
507 ParticleCacheKey **path_cache,
508 const ParticleSource particle_source,
509 const int global_offset,
510 const int start_index,
511 const int num_path_keys,
512 const int num_uv_layers,
513 const int num_col_layers,
514 const MTFace **mtfaces,
515 const MCol **mcols,
516 uint *uv_id,
517 uint *col_id,
518 float (***r_parent_uvs)[2],
519 MCol ***r_parent_mcol,
522 ParticleHairCache *hair_cache)
523{
524 const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
525 const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
526 if (is_simple && *r_parent_uvs == nullptr) {
527 /* TODO(sergey): For edit mode it should be edit->totcached. */
528 *r_parent_uvs = static_cast<float(**)[2]>(
529 MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs"));
530 }
531 if (is_simple && *r_parent_mcol == nullptr) {
532 *r_parent_mcol = static_cast<MCol **>(
533 MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol"));
534 }
535 int curr_point = start_index;
536 for (int i = 0; i < num_path_keys; i++) {
537 ParticleCacheKey *path = path_cache[i];
538 if (path->segments <= 0) {
539 continue;
540 }
541 float tangent[3];
542 float(*uv)[2] = nullptr;
543 MCol *mcol = nullptr;
545 psmd,
546 is_simple,
547 num_col_layers,
548 is_child ? psys->child[i].parent : i,
549 is_child ? i : -1,
550 mcols,
551 *r_parent_mcol,
552 &mcol);
554 psmd,
555 is_simple,
556 num_uv_layers,
557 is_child ? psys->child[i].parent : i,
558 is_child ? i : -1,
559 mtfaces,
560 *r_parent_uvs,
561 &uv);
562 for (int j = 0; j < path->segments; j++) {
563 if (j == 0) {
564 sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
565 }
566 else {
567 sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
568 }
569 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[j].co);
570 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
571 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &i);
572 if (psmd != nullptr) {
573 for (int k = 0; k < num_uv_layers; k++) {
575 hair_cache->pos,
576 uv_id[k],
577 curr_point,
578 (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] : uv[k]);
579 }
580 for (int k = 0; k < num_col_layers; k++) {
581 /* TODO: Put the conversion outside the loop. */
582 ushort scol[4];
584 (is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] : &mcol[k],
585 scol);
586 GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
587 }
588 }
589 GPU_indexbuf_add_generic_vert(elb, curr_point);
590 curr_point++;
591 }
592 sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
593
594 int global_index = i + global_offset;
595 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[path->segments].co);
596 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
597 GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &global_index);
598
599 if (psmd != nullptr) {
600 for (int k = 0; k < num_uv_layers; k++) {
601 GPU_vertbuf_attr_set(hair_cache->pos,
602 uv_id[k],
603 curr_point,
604 (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] :
605 uv[k]);
606 }
607 for (int k = 0; k < num_col_layers; k++) {
608 /* TODO: Put the conversion outside the loop. */
609 ushort scol[4];
610 particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] :
611 &mcol[k],
612 scol);
613 GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
614 }
615 if (!is_simple) {
616 MEM_freeN(uv);
617 MEM_freeN(mcol);
618 }
619 }
620 /* Finish the segment and add restart primitive. */
621 GPU_indexbuf_add_generic_vert(elb, curr_point);
623 curr_point++;
624 }
625 return curr_point;
626}
627
629 const int num_path_keys,
630 GPUVertBufRaw *attr_step,
631 GPUVertBufRaw *length_step)
632{
633 for (int i = 0; i < num_path_keys; i++) {
634 ParticleCacheKey *path = path_cache[i];
635 if (path->segments <= 0) {
636 continue;
637 }
638 float total_len = 0.0f;
639 float *co_prev = nullptr, *seg_data_first;
640 for (int j = 0; j <= path->segments; j++) {
641 float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
642 copy_v3_v3(seg_data, path[j].co);
643 if (co_prev) {
644 total_len += len_v3v3(co_prev, path[j].co);
645 }
646 else {
647 seg_data_first = seg_data;
648 }
649 seg_data[3] = total_len;
650 co_prev = path[j].co;
651 }
652 /* Assign length value. */
653 *(float *)GPU_vertbuf_raw_step(length_step) = total_len;
654 if (total_len > 0.0f) {
655 /* Divide by total length to have a [0-1] number. */
656 for (int j = 0; j <= path->segments; j++, seg_data_first += 4) {
657 seg_data_first[3] /= total_len;
658 }
659 }
660 }
661}
662
663static float particle_key_weight(const ParticleData *particle, int strand, float t)
664{
665 const ParticleData *part = particle + strand;
666 const HairKey *hkeys = part->hair;
667 float edit_key_seg_t = 1.0f / (part->totkey - 1);
668 if (t == 1.0) {
669 return hkeys[part->totkey - 1].weight;
670 }
671
672 float interp = t / edit_key_seg_t;
673 int index = int(interp);
674 interp -= floorf(interp); /* Time between 2 edit key */
675 float s1 = hkeys[index].weight;
676 float s2 = hkeys[index + 1].weight;
677 return s1 + interp * (s2 - s1);
678}
679
681 const PTCacheEdit * /*edit*/, /* nullptr for weight data */
682 const ParticleData *particle, /* nullptr for select data */
683 ParticleCacheKey **path_cache,
684 const int start_index,
685 const int num_path_keys,
687 GPUVertBufRaw *attr_step)
688{
689 int curr_point = start_index;
690 for (int i = 0; i < num_path_keys; i++) {
691 ParticleCacheKey *path = path_cache[i];
692 if (path->segments <= 0) {
693 continue;
694 }
695 for (int j = 0; j <= path->segments; j++) {
696 EditStrandData *seg_data = (EditStrandData *)GPU_vertbuf_raw_step(attr_step);
697 copy_v3_v3(seg_data->pos, path[j].co);
698 float strand_t = float(j) / path->segments;
699 if (particle) {
700 float weight = particle_key_weight(particle, i, strand_t);
701 /* NaN or unclamped become 1.0f */
702 seg_data->selection = (weight < 1.0f) ? weight : 1.0f;
703 }
704 else {
705 /* Computed in psys_cache_edit_paths_iter(). */
706 seg_data->selection = path[j].col[0];
707 }
708 GPU_indexbuf_add_generic_vert(elb, curr_point);
709 curr_point++;
710 }
711 /* Finish the segment and add restart primitive. */
713 }
714 return curr_point;
715}
716
718 const int start_index,
719 const int num_path_keys,
720 const int res,
722{
723 int curr_point = start_index;
724 for (int i = 0; i < num_path_keys; i++) {
725 ParticleCacheKey *path = path_cache[i];
726 if (path->segments <= 0) {
727 continue;
728 }
729 for (int k = 0; k < res; k++) {
730 GPU_indexbuf_add_generic_vert(elb, curr_point++);
731 }
733 }
734 return curr_point;
735}
736
739 ParticleCacheKey **path_cache,
740 const ParticleSource particle_source,
741 const int start_index,
742 const int num_path_keys,
743 GPUVertBufRaw *data_step,
744 GPUVertBufRaw *seg_step,
745 float (***r_parent_uvs)[2],
746 GPUVertBufRaw *uv_step,
747 const MTFace **mtfaces,
748 int num_uv_layers,
749 MCol ***r_parent_mcol,
750 GPUVertBufRaw *col_step,
751 const MCol **mcols,
752 int num_col_layers)
753{
754 const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
755 const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
756 if (is_simple && *r_parent_uvs == nullptr) {
757 /* TODO(sergey): For edit mode it should be edit->totcached. */
758 *r_parent_uvs = static_cast<float(**)[2]>(
759 MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs"));
760 }
761 if (is_simple && *r_parent_mcol == nullptr) {
762 *r_parent_mcol = static_cast<MCol **>(
763 MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol"));
764 }
765 int curr_point = start_index;
766 for (int i = 0; i < num_path_keys; i++) {
767 ParticleCacheKey *path = path_cache[i];
768 if (path->segments <= 0) {
769 continue;
770 }
771
772 *(uint *)GPU_vertbuf_raw_step(data_step) = curr_point;
773 *(uint *)GPU_vertbuf_raw_step(seg_step) = path->segments;
774 curr_point += path->segments + 1;
775
776 if (psmd != nullptr) {
777 float(*uv)[2] = nullptr;
778 MCol *mcol = nullptr;
779
781 psmd,
782 is_simple,
783 num_uv_layers,
784 is_child ? psys->child[i].parent : i,
785 is_child ? i : -1,
786 mtfaces,
787 *r_parent_uvs,
788 &uv);
789
791 psmd,
792 is_simple,
793 num_col_layers,
794 is_child ? psys->child[i].parent : i,
795 is_child ? i : -1,
796 mcols,
797 *r_parent_mcol,
798 &mcol);
799
800 for (int k = 0; k < num_uv_layers; k++) {
801 float *t_uv = (float *)GPU_vertbuf_raw_step(uv_step + k);
802 copy_v2_v2(t_uv, uv[k]);
803 }
804 for (int k = 0; k < num_col_layers; k++) {
805 ushort *scol = (ushort *)GPU_vertbuf_raw_step(col_step + k);
806 particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] :
807 &mcol[k],
808 scol);
809 }
810 if (!is_simple) {
811 MEM_freeN(uv);
812 MEM_freeN(mcol);
813 }
814 }
815 }
816 return curr_point;
817}
818
820 int subdiv)
821{
822 /* Same format as proc_point_buf. */
824 "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
825
826 /* Procedural Subdiv buffer only needs to be resident in device memory. */
829
830 /* Create a destination buffer for the procedural Subdiv. Sized appropriately */
831 /* Those are points! not line segments. */
832 uint point_len = cache->final[subdiv].strands_res * cache->strands_len;
833 /* Avoid creating null sized VBO which can lead to crashes on certain platforms. */
834 point_len = max_ii(1, point_len);
835
836 GPU_vertbuf_data_alloc(*cache->final[subdiv].proc_buf, point_len);
837}
838
840 ParticleSystem *psys,
841 ModifierData *md,
842 ParticleHairCache *cache)
843{
844 int active_uv = 0;
845 int render_uv = 0;
846 int active_col = 0;
847 int render_col = 0;
848
850
851 if (psmd != nullptr && psmd->mesh_final != nullptr) {
857 }
861 if (psmd->mesh_final->active_color_attribute != nullptr) {
865 }
866 if (psmd->mesh_final->default_color_attribute != nullptr) {
870 }
871 }
872 }
873
874 GPUVertBufRaw data_step, seg_step;
875 GPUVertBufRaw uv_step[MAX_MTFACE];
876 GPUVertBufRaw *col_step = BLI_array_alloca(col_step, cache->num_col_layers);
877
878 const MTFace *mtfaces[MAX_MTFACE] = {nullptr};
879 const MCol **mcols = BLI_array_alloca(mcols, cache->num_col_layers);
880 float(**parent_uvs)[2] = nullptr;
881 MCol **parent_mcol = nullptr;
882
883 GPUVertFormat format_data = {0};
884 uint data_id = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
885
886 GPUVertFormat format_seg = {0};
887 uint seg_id = GPU_vertformat_attr_add(&format_seg, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
888
889 GPUVertFormat format_uv = {0};
890 uint uv_id = GPU_vertformat_attr_add(&format_uv, "uv", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
891
892 GPUVertFormat format_col = {0};
894 &format_col, "col", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
895
896 memset(cache->uv_layer_names, 0, sizeof(cache->uv_layer_names));
897
898 /* Strand Data */
902 GPU_vertbuf_attr_get_raw_data(cache->proc_strand_buf, data_id, &data_step);
903
907 GPU_vertbuf_attr_get_raw_data(cache->proc_strand_seg_buf, seg_id, &seg_step);
908
909 /* UV layers */
910 for (int i = 0; i < cache->num_uv_layers; i++) {
914 GPU_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]);
915
916 char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
917 const char *name = CustomData_get_layer_name(
920
921 int n = 0;
922 SNPRINTF(cache->uv_layer_names[i][n], "a%s", attr_safe_name);
923 n++;
924
925 if (i == active_uv) {
926 STRNCPY(cache->uv_layer_names[i][n], "au");
927 n++;
928 }
929 if (i == render_uv) {
930 STRNCPY(cache->uv_layer_names[i][n], "a");
931 n++;
932 }
933 }
934
936 MEM_SAFE_FREE(cache->col_tex);
938
939 cache->proc_col_buf = MEM_calloc_arrayN<gpu::VertBuf *>(cache->num_col_layers, "proc_col_buf");
940 cache->col_tex = MEM_calloc_arrayN<GPUTexture *>(cache->num_col_layers, "col_tex");
942 "col_layer_names");
943
944 /* Vertex colors */
945 for (int i = 0; i < cache->num_col_layers; i++) {
949 GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]);
950
951 char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
952 const char *name = CustomData_get_layer_name(
955
956 int n = 0;
957 SNPRINTF(cache->col_layer_names[i][n], "a%s", attr_safe_name);
958 n++;
959
960 if (i == active_col) {
961 STRNCPY(cache->col_layer_names[i][n], "ac");
962 n++;
963 }
964 if (i == render_col) {
965 STRNCPY(cache->col_layer_names[i][n], "c");
966 n++;
967 }
968 }
969
970 if (cache->num_uv_layers || cache->num_col_layers) {
972 if (cache->num_uv_layers) {
973 for (int j = 0; j < cache->num_uv_layers; j++) {
974 mtfaces[j] = (const MTFace *)CustomData_get_layer_n(
975 &psmd->mesh_final->fdata_legacy, CD_MTFACE, j);
976 }
977 }
978 if (cache->num_col_layers) {
979 for (int j = 0; j < cache->num_col_layers; j++) {
980 mcols[j] = (const MCol *)CustomData_get_layer_n(
981 &psmd->mesh_final->fdata_legacy, CD_MCOL, j);
982 }
983 }
984 }
985
986 if (edit != nullptr && edit->pathcache != nullptr) {
988 psmd,
989 edit->pathcache,
991 0,
992 edit->totcached,
993 &data_step,
994 &seg_step,
995 &parent_uvs,
996 uv_step,
997 mtfaces,
998 cache->num_uv_layers,
999 &parent_mcol,
1000 col_step,
1001 mcols,
1002 cache->num_col_layers);
1003 }
1004 else {
1005 int curr_point = 0;
1006 if ((psys->pathcache != nullptr) &&
1007 (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
1008 {
1010 psmd,
1011 psys->pathcache,
1013 0,
1014 psys->totpart,
1015 &data_step,
1016 &seg_step,
1017 &parent_uvs,
1018 uv_step,
1019 mtfaces,
1020 cache->num_uv_layers,
1021 &parent_mcol,
1022 col_step,
1023 mcols,
1024 cache->num_col_layers);
1025 }
1026 if (psys->childcache) {
1027 const int child_count = psys->totchild * psys->part->disp / 100;
1029 psmd,
1030 psys->childcache,
1032 curr_point,
1033 child_count,
1034 &data_step,
1035 &seg_step,
1036 &parent_uvs,
1037 uv_step,
1038 mtfaces,
1039 cache->num_uv_layers,
1040 &parent_mcol,
1041 col_step,
1042 mcols,
1043 cache->num_col_layers);
1044 }
1045 }
1046 /* Cleanup. */
1047 if (parent_uvs != nullptr) {
1048 /* TODO(sergey): For edit mode it should be edit->totcached. */
1049 for (int i = 0; i < psys->totpart; i++) {
1050 MEM_SAFE_FREE(parent_uvs[i]);
1051 }
1052 MEM_freeN(parent_uvs);
1053 }
1054 if (parent_mcol != nullptr) {
1055 for (int i = 0; i < psys->totpart; i++) {
1056 MEM_SAFE_FREE(parent_mcol[i]);
1057 }
1058 MEM_freeN(parent_mcol);
1059 }
1060
1061 for (int i = 0; i < cache->num_uv_layers; i++) {
1062 GPU_vertbuf_use(cache->proc_uv_buf[i]);
1063 cache->uv_tex[i] = GPU_texture_create_from_vertbuf("part_uv", cache->proc_uv_buf[i]);
1064 }
1065 for (int i = 0; i < cache->num_col_layers; i++) {
1067 cache->col_tex[i] = GPU_texture_create_from_vertbuf("part_col", cache->proc_col_buf[i]);
1068 }
1069}
1070
1072 ParticleSystem *psys,
1073 ParticleHairCache *cache,
1074 int thickness_res,
1075 int subdiv)
1076{
1077 BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
1078
1079 if (cache->final[subdiv].proc_hairs[thickness_res - 1] != nullptr) {
1080 return;
1081 }
1082
1083 int verts_per_hair = cache->final[subdiv].strands_res * thickness_res;
1084 /* +1 for primitive restart */
1085 int element_count = (verts_per_hair + 1) * cache->strands_len;
1086 GPUPrimType prim_type = (thickness_res == 1) ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP;
1087
1089 "dummy", GPU_COMP_U32, 1, GPU_FETCH_INT);
1090
1092 GPU_vertbuf_data_alloc(*vbo, 1);
1093
1095 GPU_indexbuf_init_ex(&elb, prim_type, element_count, element_count);
1096
1097 if (edit != nullptr && edit->pathcache != nullptr) {
1099 edit->pathcache, 0, edit->totcached, verts_per_hair, &elb);
1100 }
1101 else {
1102 int curr_point = 0;
1103 if ((psys->pathcache != nullptr) &&
1104 (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
1105 {
1107 psys->pathcache, 0, psys->totpart, verts_per_hair, &elb);
1108 }
1109 if (psys->childcache) {
1110 const int child_count = psys->totchild * psys->part->disp / 100;
1112 psys->childcache, curr_point, child_count, verts_per_hair, &elb);
1113 }
1114 }
1115
1116 cache->final[subdiv].proc_hairs[thickness_res - 1] = GPU_batch_create_ex(
1118}
1119
1121 ParticleSystem *psys,
1122 ParticleHairCache *cache,
1123 GPUMaterial * /*gpu_material*/)
1124{
1125 if (cache->proc_point_buf == nullptr) {
1126 /* initialize vertex format */
1127 GPUVertFormat pos_format = {0};
1129 &pos_format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1130
1134
1135 GPUVertBufRaw pos_step;
1136 GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step);
1137
1138 GPUVertFormat length_format = {0};
1139 uint length_id = GPU_vertformat_attr_add(
1140 &length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
1141
1145
1146 GPUVertBufRaw length_step;
1147 GPU_vertbuf_attr_get_raw_data(cache->proc_length_buf, length_id, &length_step);
1148
1149 if (edit != nullptr && edit->pathcache != nullptr) {
1151 edit->pathcache, edit->totcached, &pos_step, &length_step);
1152 }
1153 else {
1154 if ((psys->pathcache != nullptr) &&
1155 (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
1156 {
1158 psys->pathcache, psys->totpart, &pos_step, &length_step);
1159 }
1160 if (psys->childcache) {
1161 const int child_count = psys->totchild * psys->part->disp / 100;
1163 psys->childcache, child_count, &pos_step, &length_step);
1164 }
1165 }
1166 }
1167}
1168
1170 ParticleSystem *psys,
1171 ModifierData *md,
1172 ParticleHairCache *hair_cache)
1173{
1174 if (hair_cache->pos != nullptr && hair_cache->indices != nullptr) {
1175 return;
1176 }
1177
1178 int curr_point = 0;
1180
1181 GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
1183
1184 GPUVertFormat format = {0};
1186 uint *uv_id = nullptr;
1187 uint *col_id = nullptr;
1188 int num_uv_layers = 0;
1189 int num_col_layers = 0;
1190 int active_uv = 0;
1191 int active_col = 0;
1192 const MTFace **mtfaces = nullptr;
1193 const MCol **mcols = nullptr;
1194 float(**parent_uvs)[2] = nullptr;
1195 MCol **parent_mcol = nullptr;
1196
1197 if (psmd != nullptr) {
1201 }
1203 num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->corner_data,
1205 if (psmd->mesh_final->active_color_attribute != nullptr) {
1209 }
1210 }
1211 }
1212
1216
1217 if (psmd) {
1218 uv_id = MEM_malloc_arrayN<uint>(num_uv_layers, "UV attr format");
1219 col_id = MEM_malloc_arrayN<uint>(num_col_layers, "Col attr format");
1220
1221 for (int i = 0; i < num_uv_layers; i++) {
1222
1223 char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
1224 const char *name = CustomData_get_layer_name(
1227
1228 SNPRINTF(uuid, "a%s", attr_safe_name);
1230
1231 if (i == active_uv) {
1233 }
1234 }
1235
1236 for (int i = 0; i < num_col_layers; i++) {
1237 char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
1238 const char *name = CustomData_get_layer_name(
1241
1242 SNPRINTF(uuid, "a%s", attr_safe_name);
1244
1245 if (i == active_col) {
1247 }
1248 }
1249 }
1250
1252 GPU_vertbuf_data_alloc(*hair_cache->pos, hair_cache->point_len);
1253
1255 GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len);
1256
1257 if (num_uv_layers || num_col_layers) {
1259 if (num_uv_layers) {
1260 mtfaces = static_cast<const MTFace **>(
1261 MEM_mallocN(sizeof(*mtfaces) * num_uv_layers, "Faces UV layers"));
1262 for (int i = 0; i < num_uv_layers; i++) {
1263 mtfaces[i] = (const MTFace *)CustomData_get_layer_n(
1265 }
1266 }
1267 if (num_col_layers) {
1268 mcols = static_cast<const MCol **>(
1269 MEM_mallocN(sizeof(*mcols) * num_col_layers, "Color layers"));
1270 for (int i = 0; i < num_col_layers; i++) {
1271 mcols[i] = (const MCol *)CustomData_get_layer_n(
1272 &psmd->mesh_final->fdata_legacy, CD_MCOL, i);
1273 }
1274 }
1275 }
1276
1277 if (edit != nullptr && edit->pathcache != nullptr) {
1278 curr_point = particle_batch_cache_fill_segments(psys,
1279 psmd,
1280 edit->pathcache,
1282 0,
1283 0,
1284 edit->totcached,
1285 num_uv_layers,
1286 num_col_layers,
1287 mtfaces,
1288 mcols,
1289 uv_id,
1290 col_id,
1291 &parent_uvs,
1292 &parent_mcol,
1293 &elb,
1294 &attr_id,
1295 hair_cache);
1296 }
1297 else {
1298 if ((psys->pathcache != nullptr) &&
1299 (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
1300 {
1301 curr_point = particle_batch_cache_fill_segments(psys,
1302 psmd,
1303 psys->pathcache,
1305 0,
1306 0,
1307 psys->totpart,
1308 num_uv_layers,
1309 num_col_layers,
1310 mtfaces,
1311 mcols,
1312 uv_id,
1313 col_id,
1314 &parent_uvs,
1315 &parent_mcol,
1316 &elb,
1317 &attr_id,
1318 hair_cache);
1319 }
1320 if (psys->childcache != nullptr) {
1321 const int child_count = psys->totchild * psys->part->disp / 100;
1322 curr_point = particle_batch_cache_fill_segments(psys,
1323 psmd,
1324 psys->childcache,
1326 psys->totpart,
1327 curr_point,
1328 child_count,
1329 num_uv_layers,
1330 num_col_layers,
1331 mtfaces,
1332 mcols,
1333 uv_id,
1334 col_id,
1335 &parent_uvs,
1336 &parent_mcol,
1337 &elb,
1338 &attr_id,
1339 hair_cache);
1340 }
1341 }
1342 /* Cleanup. */
1343 if (parent_uvs != nullptr) {
1344 /* TODO(sergey): For edit mode it should be edit->totcached. */
1345 for (int i = 0; i < psys->totpart; i++) {
1346 MEM_SAFE_FREE(parent_uvs[i]);
1347 }
1348 MEM_freeN(parent_uvs);
1349 }
1350 if (parent_mcol != nullptr) {
1351 for (int i = 0; i < psys->totpart; i++) {
1352 MEM_SAFE_FREE(parent_mcol[i]);
1353 }
1354 MEM_freeN(parent_mcol);
1355 }
1356 if (num_uv_layers) {
1357 MEM_freeN(mtfaces);
1358 }
1359 if (num_col_layers) {
1360 MEM_freeN(mcols);
1361 }
1362 if (psmd != nullptr) {
1363 MEM_freeN(uv_id);
1364 }
1365 hair_cache->indices = GPU_indexbuf_build(&elb);
1366}
1367
1369 ParticleSystem *psys,
1370 ParticlePointCache *point_cache)
1371{
1372 if (point_cache->pos != nullptr) {
1373 return;
1374 }
1375
1376 int i, curr_point;
1377 ParticleData *pa;
1379 ParticleSimulationData sim = {nullptr};
1380 const DRWContext *draw_ctx = DRW_context_get();
1381
1382 sim.depsgraph = draw_ctx->depsgraph;
1383 sim.scene = draw_ctx->scene;
1384 sim.ob = object;
1385 sim.psys = psys;
1386 sim.psmd = psys_get_modifier(object, psys);
1387 psys_sim_data_init(&sim);
1388
1389 GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
1390
1391 static uint pos_id, rot_id, val_id;
1392 static const GPUVertFormat format = [&]() {
1394 pos_id = GPU_vertformat_attr_add(&format, "part_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1395 val_id = GPU_vertformat_attr_add(&format, "part_val", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
1396 rot_id = GPU_vertformat_attr_add(&format, "part_rot", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1397 return format;
1398 }();
1399
1401 GPU_vertbuf_data_alloc(*point_cache->pos, psys->totpart);
1402
1403 for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
1404 state.time = DEG_get_ctime(draw_ctx->depsgraph);
1405 if (!psys_get_particle_state(&sim, i, &state, false)) {
1406 continue;
1407 }
1408
1409 float val;
1410
1411 GPU_vertbuf_attr_set(point_cache->pos, pos_id, curr_point, state.co);
1412 GPU_vertbuf_attr_set(point_cache->pos, rot_id, curr_point, state.rot);
1413
1414 switch (psys->part->draw_col) {
1415 case PART_DRAW_COL_VEL:
1416 val = len_v3(state.vel) / psys->part->color_vec_max;
1417 break;
1418 case PART_DRAW_COL_ACC:
1419 val = len_v3v3(state.vel, pa->prev_state.vel) /
1420 ((state.time - pa->prev_state.time) * psys->part->color_vec_max);
1421 break;
1422 default:
1423 val = -1.0f;
1424 break;
1425 }
1426
1427 GPU_vertbuf_attr_set(point_cache->pos, val_id, curr_point, &val);
1428
1429 curr_point++;
1430 }
1431
1432 if (curr_point != psys->totpart) {
1433 GPU_vertbuf_data_resize(*point_cache->pos, curr_point);
1434 }
1435
1436 psys_sim_data_free(&sim);
1437}
1438
1440 ParticleSystem *psys,
1441 PTCacheEdit *edit)
1442{
1443 if (edit->psys == nullptr) {
1444 return;
1445 }
1446 /* NOTE: Get flag from particle system coming from drawing object.
1447 * this is where depsgraph will be setting flags to.
1448 */
1449 const DRWContext *draw_ctx = DRW_context_get();
1450 Scene *scene_orig = DEG_get_original(draw_ctx->scene);
1451 Object *object_orig = DEG_get_original(object_eval);
1452 if (psys->flag & PSYS_HAIR_UPDATED) {
1453 PE_update_object(draw_ctx->depsgraph, scene_orig, object_orig, 0);
1454 psys->flag &= ~PSYS_HAIR_UPDATED;
1455 }
1456 if (edit->pathcache == nullptr) {
1457 Depsgraph *depsgraph = draw_ctx->depsgraph;
1459 scene_orig,
1460 object_orig,
1461 edit,
1464 }
1465}
1466
1467static void drw_particle_update_ptcache(Object *object_eval, ParticleSystem *psys)
1468{
1469 if ((object_eval->mode & OB_MODE_PARTICLE_EDIT) == 0) {
1470 return;
1471 }
1472 const DRWContext *draw_ctx = DRW_context_get();
1473 Scene *scene_orig = DEG_get_original(draw_ctx->scene);
1474 Object *object_orig = DEG_get_original(object_eval);
1475 PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, object_orig);
1476 if (edit != nullptr) {
1477 drw_particle_update_ptcache_edit(object_eval, psys, edit);
1478 }
1479}
1480
1487
1489 ParticleSystem *psys,
1490 ModifierData *md,
1491 PTCacheEdit *edit,
1492 ParticleDrawSource *r_draw_source)
1493{
1494 const DRWContext *draw_ctx = DRW_context_get();
1495 r_draw_source->object = object;
1496 r_draw_source->psys = psys;
1497 r_draw_source->md = md;
1498 r_draw_source->edit = edit;
1499 if (psys_in_edit_mode(draw_ctx->depsgraph, psys)) {
1500 r_draw_source->object = DEG_get_original(object);
1501 r_draw_source->psys = psys_orig_get(psys);
1502 }
1503}
1504
1506 ParticleSystem *psys,
1507 ModifierData *md)
1508{
1510 if (cache->hair.hairs == nullptr) {
1511 drw_particle_update_ptcache(object, psys);
1512 ParticleDrawSource source;
1513 drw_particle_get_hair_source(object, psys, md, nullptr, &source);
1514 ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
1515 particle_batch_cache_ensure_pos_and_seg(source.edit, source.psys, source.md, &cache->hair);
1516 cache->hair.hairs = GPU_batch_create(
1517 GPU_PRIM_LINE_STRIP, cache->hair.pos, cache->hair.indices);
1518 }
1519 return cache->hair.hairs;
1520}
1521
1523{
1525
1526 if (cache->point.points == nullptr) {
1527 particle_batch_cache_ensure_pos(object, psys, &cache->point);
1528 cache->point.points = GPU_batch_create(GPU_PRIM_POINTS, cache->point.pos, nullptr);
1529 }
1530
1531 return cache->point.points;
1532}
1533
1535 ParticleSystem *psys,
1536 ModifierData * /*md*/,
1537 ParticleHairCache *hair_cache,
1538 bool use_weight)
1539{
1540 if (hair_cache->pos != nullptr && hair_cache->indices != nullptr) {
1541 return;
1542 }
1543
1544 ParticleData *particle = (use_weight) ? psys->particles : nullptr;
1545
1546 GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
1548
1549 GPUVertBufRaw data_step;
1551 uint pos_id, selection_id;
1552 const GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &selection_id);
1553
1554 hair_cache->pos = GPU_vertbuf_create_with_format(*edit_point_format);
1555 GPU_vertbuf_data_alloc(*hair_cache->pos, hair_cache->point_len);
1556 GPU_vertbuf_attr_get_raw_data(hair_cache->pos, pos_id, &data_step);
1557
1558 GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len);
1559
1560 if (edit != nullptr && edit->pathcache != nullptr) {
1562 edit, particle, edit->pathcache, 0, edit->totcached, &elb, &data_step);
1563 }
1564 hair_cache->indices = GPU_indexbuf_build(&elb);
1565}
1566
1568 ParticleSystem *psys,
1569 PTCacheEdit *edit,
1570 bool use_weight)
1571{
1573 if (cache->edit_is_weight != use_weight) {
1576 }
1577 if (cache->edit_hair.hairs != nullptr) {
1578 return cache->edit_hair.hairs;
1579 }
1580 drw_particle_update_ptcache_edit(object, psys, edit);
1581 ensure_seg_pt_count(edit, psys, &cache->edit_hair);
1582 particle_batch_cache_ensure_edit_pos_and_seg(edit, psys, nullptr, &cache->edit_hair, use_weight);
1585 cache->edit_is_weight = use_weight;
1586 return cache->edit_hair.hairs;
1587}
1588
1590{
1591 if (cache->edit_inner_pos != nullptr) {
1592 return;
1593 }
1594 cache->edit_inner_point_len = 0;
1595 for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1596 const PTCacheEditPoint *point = &edit->points[point_index];
1597 if (point->flag & PEP_HIDE) {
1598 continue;
1599 }
1600 BLI_assert(point->totkey >= 1);
1601 cache->edit_inner_point_len += (point->totkey - 1);
1602 }
1603}
1604
1606 ParticleBatchCache *cache)
1607{
1608 if (cache->edit_inner_pos != nullptr) {
1609 return;
1610 }
1611
1612 uint pos_id, selection_id;
1613 const GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &selection_id);
1614
1615 cache->edit_inner_pos = GPU_vertbuf_create_with_format(*edit_point_format);
1617
1618 int global_key_index = 0;
1619 for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1620 const PTCacheEditPoint *point = &edit->points[point_index];
1621 if (point->flag & PEP_HIDE) {
1622 continue;
1623 }
1624 for (int key_index = 0; key_index < point->totkey - 1; key_index++) {
1625 PTCacheEditKey *key = &point->keys[key_index];
1626 float selection = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
1627 GPU_vertbuf_attr_set(cache->edit_inner_pos, pos_id, global_key_index, key->world_co);
1628 GPU_vertbuf_attr_set(cache->edit_inner_pos, selection_id, global_key_index, &selection);
1629 global_key_index++;
1630 }
1631 }
1632}
1633
1635 ParticleSystem *psys,
1636 PTCacheEdit *edit)
1637{
1639 if (cache->edit_inner_points != nullptr) {
1640 return cache->edit_inner_points;
1641 }
1642 drw_particle_update_ptcache_edit(object, psys, edit);
1643 ensure_edit_inner_points_count(edit, cache);
1646 return cache->edit_inner_points;
1647}
1648
1650{
1651 if (cache->edit_tip_pos != nullptr) {
1652 return;
1653 }
1654 cache->edit_tip_point_len = 0;
1655 for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1656 const PTCacheEditPoint *point = &edit->points[point_index];
1657 if (point->flag & PEP_HIDE) {
1658 continue;
1659 }
1660 cache->edit_tip_point_len += 1;
1661 }
1662}
1663
1665{
1666 if (cache->edit_tip_pos != nullptr) {
1667 return;
1668 }
1669
1670 uint pos_id, selection_id;
1671 const GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &selection_id);
1672
1673 cache->edit_tip_pos = GPU_vertbuf_create_with_format(*edit_point_format);
1675
1676 int global_point_index = 0;
1677 for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1678 const PTCacheEditPoint *point = &edit->points[point_index];
1679 if (point->flag & PEP_HIDE) {
1680 continue;
1681 }
1682 PTCacheEditKey *key = &point->keys[point->totkey - 1];
1683 float selection = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
1684
1685 GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, global_point_index, key->world_co);
1686 GPU_vertbuf_attr_set(cache->edit_tip_pos, selection_id, global_point_index, &selection);
1687 global_point_index++;
1688 }
1689}
1690
1692 ParticleSystem *psys,
1693 PTCacheEdit *edit)
1694{
1696 if (cache->edit_tip_points != nullptr) {
1697 return cache->edit_tip_points;
1698 }
1699 drw_particle_update_ptcache_edit(object, psys, edit);
1700 ensure_edit_tip_points_count(edit, cache);
1703 return cache->edit_tip_points;
1704}
1705
1707{
1708 float4x4 dupli_mat = float4x4::identity();
1709
1710 if ((ob_ref.dupli_parent != nullptr) && (ob_ref.dupli_object != nullptr)) {
1711 if (ob_ref.dupli_object->type & OB_DUPLICOLLECTION) {
1712 Collection *collection = ob_ref.dupli_parent->instance_collection;
1713 if (collection != nullptr) {
1714 dupli_mat[3] -= float4(float3(collection->instance_offset), 0.0f);
1715 }
1716 dupli_mat = ob_ref.dupli_parent->object_to_world() * dupli_mat;
1717 }
1718 else {
1719 dupli_mat = ob_ref.object->object_to_world() *
1720 math::invert(ob_ref.dupli_object->ob->object_to_world());
1721 }
1722 }
1723 return dupli_mat;
1724}
1725
1727 ParticleSystem *psys,
1728 ModifierData *md,
1729 ParticleHairCache **r_hair_cache,
1730 GPUMaterial *gpu_material,
1731 int subdiv,
1732 int thickness_res)
1733{
1734 bool need_ft_update = false;
1735
1736 drw_particle_update_ptcache(object, psys);
1737
1738 ParticleDrawSource source;
1739 drw_particle_get_hair_source(object, psys, md, nullptr, &source);
1740
1741 ParticleSettings *part = source.psys->part;
1743 *r_hair_cache = &cache->hair;
1744
1745 (*r_hair_cache)->final[subdiv].strands_res = 1 << (part->draw_step + subdiv);
1746
1747 /* Refreshed on combing and simulation. */
1748 if ((*r_hair_cache)->proc_point_buf == nullptr ||
1749 (gpu_material && (*r_hair_cache)->proc_length_buf == nullptr))
1750 {
1751 ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
1753 source.edit, source.psys, &cache->hair, gpu_material);
1754 need_ft_update = true;
1755 }
1756
1757 /* Refreshed if active layer or custom data changes. */
1758 if ((*r_hair_cache)->proc_strand_buf == nullptr) {
1760 source.edit, source.psys, source.md, &cache->hair);
1761 }
1762
1763 /* Refreshed only on subdiv count change. */
1764 if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) {
1766 need_ft_update = true;
1767 }
1768 if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) {
1770 source.edit, source.psys, &cache->hair, thickness_res, subdiv);
1771 }
1772
1773 return need_ft_update;
1774}
1775
1776} // 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:2153
#define DMCACHE_NOTFOUND
struct ParticleSystem * psys_orig_get(struct ParticleSystem *psys)
Definition particle.cc:659
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:3653
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:632
#define DMCACHE_ISCHILD
@ BKE_PARTICLE_BATCH_DIRTY_ALL
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:591
bool psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, bool always)
Definition particle.cc:4877
#define PEP_HIDE
#define PEK_SELECT
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
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
ATTR_WARN_UNUSED_RESULT const size_t num
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
unsigned int uint
unsigned short ushort
#define UNLIKELY(x)
#define ELEM(...)
@ DAG_EVAL_RENDER
float DEG_get_ctime(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
T * DEG_get_original(T *id)
Object groups, one object can be in many groups at once.
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT2
@ OB_MODE_PARTICLE_EDIT
@ OB_DUPLICOLLECTION
@ PART_CHILD_PARTICLES
@ PART_FROM_VOLUME
@ PART_FROM_FACE
@ PART_DRAW_COL_ACC
@ PART_DRAW_COL_VEL
@ PSYS_HAIR_UPDATED
@ PART_DRAW_PARENT
struct ParticleSystem ParticleSystem
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:51
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:148
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:204
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:50
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:41
#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)
#define GPU_TEXTURE_FREE_SAFE(texture)
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
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
@ GPU_FETCH_INT
void GPU_vertformat_alias_add(GPUVertFormat *, blender::StringRef alias)
void GPU_vertformat_safe_attr_name(blender::StringRef attr_name, char *r_safe_name, uint max_len)
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
static constexpr int GPU_MAX_SAFE_ATTR_NAME
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, const GPUVertCompType comp_type, const uint comp_len, const GPUVertFetchMode fetch_mode)
@ GPU_COMP_U16
@ GPU_COMP_F32
@ GPU_COMP_I32
@ GPU_COMP_U32
Read Guarded memory(de)allocation.
BPy_StructRNA * depsgraph
#define floorf(x)
const DRWContext * DRW_context_get()
#define MAX_THICKRES
#define MAX_HAIR_SUBDIV
struct @242053044010324116347033273112253060004051364061::@373043131300025057314200265134167265161140142363 attr_id
#define MEM_SAFE_FREE(v)
#define MAX_MTFACE
format
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float interp(const float a, const float b, const float t)
Definition math_base.h:502
MINLINE unsigned short unit_float_to_ushort_clamp(float val)
float BLI_color_from_srgb_table[256]
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 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)
float4x4 DRW_particles_dupli_matrix_get(const ObjectRef &ob_ref)
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 const GPUVertFormat * edit_points_vert_format_get(uint *r_pos_id, uint *r_selection_id)
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])
CartesianBasis invert(const CartesianBasis &basis)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 3 > float3
static bool is_child(const Object *ob, const Object *parent)
Depsgraph * depsgraph
Scene * scene
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 Collection * instance_collection
struct PTCacheEditKey * keys
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
DupliObject * dupli_object
i
Definition text_draw.cc:230