Blender  V3.3
draw_cache_impl_particles.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2017 Blender Foundation. All rights reserved. */
3 
10 #include "DRW_render.h"
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_alloca.h"
15 #include "BLI_ghash.h"
16 #include "BLI_math_vector.h"
17 #include "BLI_string.h"
18 #include "BLI_utildefines.h"
19 
20 #include "DNA_customdata_types.h"
21 #include "DNA_mesh_types.h"
22 #include "DNA_meshdata_types.h"
23 #include "DNA_modifier_types.h"
24 #include "DNA_particle_types.h"
25 
26 #include "BKE_customdata.h"
27 #include "BKE_mesh.h"
29 #include "BKE_particle.h"
30 #include "BKE_pointcache.h"
31 
32 #include "ED_particle.h"
33 
34 #include "GPU_batch.h"
35 #include "GPU_material.h"
36 
37 #include "DEG_depsgraph_query.h"
38 
39 #include "draw_cache_impl.h" /* own include */
40 #include "draw_hair_private.h"
41 
43 
44 /* ---------------------------------------------------------------------- */
45 /* Particle GPUBatch Cache */
46 
47 typedef struct ParticlePointCache {
50  int elems_len;
51  int point_len;
53 
54 typedef struct ParticleBatchCache {
55  /* Object mode strands for hair and points for particle,
56  * strands for paths when in edit mode.
57  */
58  ParticleHairCache hair; /* Used for hair strands */
59  ParticlePointCache point; /* Used for particle points. */
60 
61  /* Control points when in edit mode. */
63 
66 
70 
74 
75  /* Settings to determine if cache is invalid. */
76  bool is_dirty;
79 
80 /* GPUBatch cache management. */
81 
82 typedef struct HairAttributeID {
87 
88 typedef struct EditStrandData {
89  float pos[3];
90  float color;
92 
93 static GPUVertFormat *edit_points_vert_format_get(uint *r_pos_id, uint *r_color_id)
94 {
95  static GPUVertFormat edit_point_format = {0};
96  static uint pos_id, color_id;
97  if (edit_point_format.attr_len == 0) {
98  /* Keep in sync with EditStrandData */
99  pos_id = GPU_vertformat_attr_add(&edit_point_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
100  color_id = GPU_vertformat_attr_add(
101  &edit_point_format, "color", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
102  }
103  *r_pos_id = pos_id;
104  *r_color_id = color_id;
105  return &edit_point_format;
106 }
107 
109 {
110  ParticleBatchCache *cache = psys->batch_cache;
111 
112  if (cache == NULL) {
113  return false;
114  }
115 
116  if (cache->is_dirty == false) {
117  return true;
118  }
119 
120  return false;
121 
122  return true;
123 }
124 
126 {
127  ParticleBatchCache *cache = psys->batch_cache;
128 
129  if (!cache) {
130  cache = psys->batch_cache = MEM_callocN(sizeof(*cache), __func__);
131  }
132  else {
133  memset(cache, 0, sizeof(*cache));
134  }
135 
136  cache->is_dirty = false;
137 }
138 
140 {
141  if (!particle_batch_cache_valid(psys)) {
144  }
145  return psys->batch_cache;
146 }
147 
149 {
150  ParticleBatchCache *cache = psys->batch_cache;
151  if (cache == NULL) {
152  return;
153  }
154  switch (mode) {
156  cache->is_dirty = true;
157  break;
158  default:
159  BLI_assert(0);
160  }
161 }
162 
164 {
165  GPU_BATCH_DISCARD_SAFE(point_cache->points);
166  GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
167 }
168 
170 {
171  /* TODO: more granular update tagging. */
174  DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex);
175  DRW_TEXTURE_FREE_SAFE(hair_cache->length_tex);
176 
179  DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex);
181 
182  for (int i = 0; i < MAX_MTFACE; i++) {
183  GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]);
184  DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]);
185  }
186  for (int i = 0; i < hair_cache->num_col_layers; i++) {
187  GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]);
188  DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]);
189  }
190 
191  for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
192  GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf);
193  DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex);
194  for (int j = 0; j < MAX_THICKRES; j++) {
195  GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]);
196  }
197  }
198 
199  /* "Normal" legacy hairs */
200  GPU_BATCH_DISCARD_SAFE(hair_cache->hairs);
201  GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
202  GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
203 }
204 
206 {
207  ParticleBatchCache *cache = psys->batch_cache;
208  if (!cache) {
209  return;
210  }
211 
214 
216 
221 }
222 
224 {
226  MEM_SAFE_FREE(hair->col_tex);
228 }
229 
231 {
233 
234  ParticleBatchCache *cache = psys->batch_cache;
235 
236  if (cache) {
239  }
240 
241  MEM_SAFE_FREE(psys->batch_cache);
242 }
243 
245  const int num_path_cache_keys,
246  ParticleHairCache *hair_cache)
247 {
248  for (int i = 0; i < num_path_cache_keys; i++) {
249  ParticleCacheKey *path = pathcache[i];
250  if (path->segments > 0) {
251  hair_cache->strands_len++;
252  hair_cache->elems_len += path->segments + 2;
253  hair_cache->point_len += path->segments + 1;
254  }
255  }
256 }
257 
259  ParticleSystem *psys,
260  ParticleHairCache *hair_cache)
261 {
262  if ((hair_cache->pos != NULL && hair_cache->indices != NULL) ||
263  (hair_cache->proc_point_buf != NULL)) {
264  return;
265  }
266 
267  hair_cache->strands_len = 0;
268  hair_cache->elems_len = 0;
269  hair_cache->point_len = 0;
270 
271  if (edit != NULL && edit->pathcache != NULL) {
272  count_cache_segment_keys(edit->pathcache, edit->totcached, hair_cache);
273  }
274  else {
275  if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
276  count_cache_segment_keys(psys->pathcache, psys->totpart, hair_cache);
277  }
278  if (psys->childcache) {
279  const int child_count = psys->totchild * psys->part->disp / 100;
280  count_cache_segment_keys(psys->childcache, child_count, hair_cache);
281  }
282  }
283 }
284 
285 static void particle_pack_mcol(MCol *mcol, ushort r_scol[3])
286 {
287  /* Convert to linear ushort and swizzle */
291 }
292 
293 /* Used by parent particles and simple children. */
296  const int num_uv_layers,
297  const int parent_index,
298  const MTFace **mtfaces,
299  float (*r_uv)[2])
300 {
301  if (psmd == NULL) {
302  return;
303  }
304  const int emit_from = psmd->psys->part->from;
305  if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
306  return;
307  }
308  ParticleData *particle = &psys->particles[parent_index];
309  int num = particle->num_dmcache;
311  if (particle->num < psmd->mesh_final->totface) {
312  num = particle->num;
313  }
314  }
315  if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
316  MFace *mface = &psmd->mesh_final->mface[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 == NULL) {
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) {
341  num = particle->num;
342  }
343  }
344  if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
345  MFace *mface = &psmd->mesh_final->mface[num];
346  for (int j = 0; j < num_col_layers; j++) {
347  /* CustomDataLayer CD_MCOL has 4 structs per face. */
348  psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
349  }
350  }
351 }
352 
353 /* Used by interpolated children. */
356  const int num_uv_layers,
357  const int child_index,
358  const MTFace **mtfaces,
359  float (*r_uv)[2])
360 {
361  if (psmd == NULL) {
362  return;
363  }
364  const int emit_from = psmd->psys->part->from;
365  if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
366  return;
367  }
368  ChildParticle *particle = &psys->child[child_index];
369  int num = particle->num;
370  if (num != DMCACHE_NOTFOUND) {
371  MFace *mface = &psmd->mesh_final->mface[num];
372  for (int j = 0; j < num_uv_layers; j++) {
373  psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]);
374  }
375  }
376 }
377 
380  const int num_col_layers,
381  const int child_index,
382  const MCol **mcols,
383  MCol *r_mcol)
384 {
385  if (psmd == NULL) {
386  return;
387  }
388  const int emit_from = psmd->psys->part->from;
389  if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
390  return;
391  }
392  ChildParticle *particle = &psys->child[child_index];
393  int num = particle->num;
394  if (num != DMCACHE_NOTFOUND) {
395  MFace *mface = &psmd->mesh_final->mface[num];
396  for (int j = 0; j < num_col_layers; j++) {
397  /* CustomDataLayer CD_MCOL has 4 structs per face. */
398  psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
399  }
400  }
401 }
402 
405  const bool is_simple,
406  const int num_uv_layers,
407  const int parent_index,
408  const int child_index,
409  const MTFace **mtfaces,
410  float (**r_parent_uvs)[2],
411  float (**r_uv)[2])
412 {
413  if (psmd == NULL) {
414  return;
415  }
416  if (is_simple) {
417  if (r_parent_uvs[parent_index] != NULL) {
418  *r_uv = r_parent_uvs[parent_index];
419  }
420  else {
421  *r_uv = MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs");
422  }
423  }
424  else {
425  *r_uv = MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs");
426  }
427  if (child_index == -1) {
428  /* Calculate UVs for parent particles. */
429  if (is_simple) {
430  r_parent_uvs[parent_index] = *r_uv;
431  }
432  particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
433  }
434  else {
435  /* Calculate UVs for child particles. */
436  if (!is_simple) {
437  particle_interpolate_children_uvs(psys, psmd, num_uv_layers, child_index, mtfaces, *r_uv);
438  }
439  else if (!r_parent_uvs[psys->child[child_index].parent]) {
440  r_parent_uvs[psys->child[child_index].parent] = *r_uv;
441  particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
442  }
443  }
444 }
445 
448  const bool is_simple,
449  const int num_col_layers,
450  const int parent_index,
451  const int child_index,
452  const MCol **mcols,
453  MCol **r_parent_mcol,
454  MCol **r_mcol)
455 {
456  if (psmd == NULL) {
457  return;
458  }
459  if (is_simple) {
460  if (r_parent_mcol[parent_index] != NULL) {
461  *r_mcol = r_parent_mcol[parent_index];
462  }
463  else {
464  *r_mcol = MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol");
465  }
466  }
467  else {
468  *r_mcol = MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol");
469  }
470  if (child_index == -1) {
471  /* Calculate MCols for parent particles. */
472  if (is_simple) {
473  r_parent_mcol[parent_index] = *r_mcol;
474  }
475  particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
476  }
477  else {
478  /* Calculate MCols for child particles. */
479  if (!is_simple) {
480  particle_interpolate_children_mcol(psys, psmd, num_col_layers, child_index, mcols, *r_mcol);
481  }
482  else if (!r_parent_mcol[psys->child[child_index].parent]) {
483  r_parent_mcol[psys->child[child_index].parent] = *r_mcol;
484  particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
485  }
486  }
487 }
488 
489 /* Will return last filled index. */
490 typedef enum ParticleSource {
496  ParticleCacheKey **path_cache,
497  const ParticleSource particle_source,
498  const int global_offset,
499  const int start_index,
500  const int num_path_keys,
501  const int num_uv_layers,
502  const int num_col_layers,
503  const MTFace **mtfaces,
504  const MCol **mcols,
505  uint *uv_id,
506  uint *col_id,
507  float (***r_parent_uvs)[2],
508  MCol ***r_parent_mcol,
509  GPUIndexBufBuilder *elb,
511  ParticleHairCache *hair_cache)
512 {
513  const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
514  const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
515  if (is_simple && *r_parent_uvs == NULL) {
516  /* TODO(sergey): For edit mode it should be edit->totcached. */
517  *r_parent_uvs = MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs");
518  }
519  if (is_simple && *r_parent_mcol == NULL) {
520  *r_parent_mcol = MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol");
521  }
522  int curr_point = start_index;
523  for (int i = 0; i < num_path_keys; i++) {
524  ParticleCacheKey *path = path_cache[i];
525  if (path->segments <= 0) {
526  continue;
527  }
528  float tangent[3];
529  float(*uv)[2] = NULL;
530  MCol *mcol = NULL;
532  psmd,
533  is_simple,
534  num_col_layers,
535  is_child ? psys->child[i].parent : i,
536  is_child ? i : -1,
537  mcols,
538  *r_parent_mcol,
539  &mcol);
541  psmd,
542  is_simple,
543  num_uv_layers,
544  is_child ? psys->child[i].parent : i,
545  is_child ? i : -1,
546  mtfaces,
547  *r_parent_uvs,
548  &uv);
549  for (int j = 0; j < path->segments; j++) {
550  if (j == 0) {
551  sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
552  }
553  else {
554  sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
555  }
556  GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[j].co);
557  GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
558  GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &i);
559  if (psmd != NULL) {
560  for (int k = 0; k < num_uv_layers; k++) {
562  hair_cache->pos,
563  uv_id[k],
564  curr_point,
565  (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] : uv[k]);
566  }
567  for (int k = 0; k < num_col_layers; k++) {
568  /* TODO: Put the conversion outside the loop. */
569  ushort scol[4];
571  (is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] : &mcol[k],
572  scol);
573  GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
574  }
575  }
576  GPU_indexbuf_add_generic_vert(elb, curr_point);
577  curr_point++;
578  }
579  sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
580 
581  int global_index = i + global_offset;
582  GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[path->segments].co);
583  GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
584  GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &global_index);
585 
586  if (psmd != NULL) {
587  for (int k = 0; k < num_uv_layers; k++) {
588  GPU_vertbuf_attr_set(hair_cache->pos,
589  uv_id[k],
590  curr_point,
591  (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] :
592  uv[k]);
593  }
594  for (int k = 0; k < num_col_layers; k++) {
595  /* TODO: Put the conversion outside the loop. */
596  ushort scol[4];
597  particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] :
598  &mcol[k],
599  scol);
600  GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
601  }
602  if (!is_simple) {
603  MEM_freeN(uv);
604  MEM_freeN(mcol);
605  }
606  }
607  /* Finish the segment and add restart primitive. */
608  GPU_indexbuf_add_generic_vert(elb, curr_point);
610  curr_point++;
611  }
612  return curr_point;
613 }
614 
616  const int num_path_keys,
617  GPUVertBufRaw *attr_step,
618  GPUVertBufRaw *length_step)
619 {
620  for (int i = 0; i < num_path_keys; i++) {
621  ParticleCacheKey *path = path_cache[i];
622  if (path->segments <= 0) {
623  continue;
624  }
625  float total_len = 0.0f;
626  float *co_prev = NULL, *seg_data_first;
627  for (int j = 0; j <= path->segments; j++) {
628  float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
629  copy_v3_v3(seg_data, path[j].co);
630  if (co_prev) {
631  total_len += len_v3v3(co_prev, path[j].co);
632  }
633  else {
634  seg_data_first = seg_data;
635  }
636  seg_data[3] = total_len;
637  co_prev = path[j].co;
638  }
639  /* Assign length value. */
640  *(float *)GPU_vertbuf_raw_step(length_step) = total_len;
641  if (total_len > 0.0f) {
642  /* Divide by total length to have a [0-1] number. */
643  for (int j = 0; j <= path->segments; j++, seg_data_first += 4) {
644  seg_data_first[3] /= total_len;
645  }
646  }
647  }
648 }
649 
650 static float particle_key_weight(const ParticleData *particle, int strand, float t)
651 {
652  const ParticleData *part = particle + strand;
653  const HairKey *hkeys = part->hair;
654  float edit_key_seg_t = 1.0f / (part->totkey - 1);
655  if (t == 1.0) {
656  return hkeys[part->totkey - 1].weight;
657  }
658 
659  float interp = t / edit_key_seg_t;
660  int index = (int)interp;
661  interp -= floorf(interp); /* Time between 2 edit key */
662  float s1 = hkeys[index].weight;
663  float s2 = hkeys[index + 1].weight;
664  return s1 + interp * (s2 - s1);
665 }
666 
668  const PTCacheEdit *UNUSED(edit), /* NULL for weight data */
669  const ParticleData *particle, /* NULL for select data */
670  ParticleCacheKey **path_cache,
671  const int start_index,
672  const int num_path_keys,
673  GPUIndexBufBuilder *elb,
674  GPUVertBufRaw *attr_step)
675 {
676  int curr_point = start_index;
677  for (int i = 0; i < num_path_keys; i++) {
678  ParticleCacheKey *path = path_cache[i];
679  if (path->segments <= 0) {
680  continue;
681  }
682  for (int j = 0; j <= path->segments; j++) {
683  EditStrandData *seg_data = (EditStrandData *)GPU_vertbuf_raw_step(attr_step);
684  copy_v3_v3(seg_data->pos, path[j].co);
685  float strand_t = (float)(j) / path->segments;
686  if (particle) {
687  float weight = particle_key_weight(particle, i, strand_t);
688  /* NaN or unclamped become 1.0f */
689  seg_data->color = (weight < 1.0f) ? weight : 1.0f;
690  }
691  else {
692  /* Computed in psys_cache_edit_paths_iter(). */
693  seg_data->color = path[j].col[0];
694  }
695  GPU_indexbuf_add_generic_vert(elb, curr_point);
696  curr_point++;
697  }
698  /* Finish the segment and add restart primitive. */
700  }
701  return curr_point;
702 }
703 
705  const int start_index,
706  const int num_path_keys,
707  const int res,
708  GPUIndexBufBuilder *elb)
709 {
710  int curr_point = start_index;
711  for (int i = 0; i < num_path_keys; i++) {
712  ParticleCacheKey *path = path_cache[i];
713  if (path->segments <= 0) {
714  continue;
715  }
716  for (int k = 0; k < res; k++) {
717  GPU_indexbuf_add_generic_vert(elb, curr_point++);
718  }
720  }
721  return curr_point;
722 }
723 
726  ParticleCacheKey **path_cache,
727  const ParticleSource particle_source,
728  const int start_index,
729  const int num_path_keys,
730  GPUVertBufRaw *data_step,
731  GPUVertBufRaw *seg_step,
732  float (***r_parent_uvs)[2],
733  GPUVertBufRaw *uv_step,
734  const MTFace **mtfaces,
735  int num_uv_layers,
736  MCol ***r_parent_mcol,
737  GPUVertBufRaw *col_step,
738  const MCol **mcols,
739  int num_col_layers)
740 {
741  const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
742  const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
743  if (is_simple && *r_parent_uvs == NULL) {
744  /* TODO(sergey): For edit mode it should be edit->totcached. */
745  *r_parent_uvs = MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs");
746  }
747  if (is_simple && *r_parent_mcol == NULL) {
748  *r_parent_mcol = MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol");
749  }
750  int curr_point = start_index;
751  for (int i = 0; i < num_path_keys; i++) {
752  ParticleCacheKey *path = path_cache[i];
753  if (path->segments <= 0) {
754  continue;
755  }
756 
757  *(uint *)GPU_vertbuf_raw_step(data_step) = curr_point;
758  *(ushort *)GPU_vertbuf_raw_step(seg_step) = path->segments;
759  curr_point += path->segments + 1;
760 
761  if (psmd != NULL) {
762  float(*uv)[2] = NULL;
763  MCol *mcol = NULL;
764 
766  psmd,
767  is_simple,
768  num_uv_layers,
769  is_child ? psys->child[i].parent : i,
770  is_child ? i : -1,
771  mtfaces,
772  *r_parent_uvs,
773  &uv);
774 
776  psmd,
777  is_simple,
778  num_col_layers,
779  is_child ? psys->child[i].parent : i,
780  is_child ? i : -1,
781  mcols,
782  *r_parent_mcol,
783  &mcol);
784 
785  for (int k = 0; k < num_uv_layers; k++) {
786  float *t_uv = (float *)GPU_vertbuf_raw_step(uv_step + k);
787  copy_v2_v2(t_uv, uv[k]);
788  }
789  for (int k = 0; k < num_col_layers; k++) {
790  ushort *scol = (ushort *)GPU_vertbuf_raw_step(col_step + k);
791  particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] :
792  &mcol[k],
793  scol);
794  }
795  if (!is_simple) {
796  MEM_freeN(uv);
797  MEM_freeN(mcol);
798  }
799  }
800  }
801  return curr_point;
802 }
803 
805  int subdiv)
806 {
807  /* Same format as point_tex. */
808  GPUVertFormat format = {0};
810 
812 
813  /* Create a destination buffer for the transform feedback. Sized appropriately */
814  /* Those are points! not line segments. */
815  GPU_vertbuf_data_alloc(cache->final[subdiv].proc_buf,
816  cache->final[subdiv].strands_res * cache->strands_len);
817 
818  /* Create vbo immediately to bind to texture buffer. */
819  GPU_vertbuf_use(cache->final[subdiv].proc_buf);
820 
821  cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf("part_proc",
822  cache->final[subdiv].proc_buf);
823 }
824 
826  ParticleSystem *psys,
827  ModifierData *md,
828  ParticleHairCache *cache)
829 {
830  int active_uv = 0;
831  int render_uv = 0;
832  int active_col = 0;
833  int render_col = 0;
834 
836 
837  if (psmd != NULL && psmd->mesh_final != NULL) {
842  }
848  }
849  }
850 
851  GPUVertBufRaw data_step, seg_step;
852  GPUVertBufRaw uv_step[MAX_MTFACE];
853  GPUVertBufRaw *col_step = BLI_array_alloca(col_step, cache->num_col_layers);
854 
855  const MTFace *mtfaces[MAX_MTFACE] = {NULL};
856  const MCol **mcols = BLI_array_alloca(mcols, cache->num_col_layers);
857  float(**parent_uvs)[2] = NULL;
858  MCol **parent_mcol = NULL;
859 
860  GPUVertFormat format_data = {0};
861  uint data_id = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
862 
863  GPUVertFormat format_seg = {0};
864  uint seg_id = GPU_vertformat_attr_add(&format_seg, "data", GPU_COMP_U16, 1, GPU_FETCH_INT);
865 
866  GPUVertFormat format_uv = {0};
867  uint uv_id = GPU_vertformat_attr_add(&format_uv, "uv", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
868 
869  GPUVertFormat format_col = {0};
870  uint col_id = GPU_vertformat_attr_add(
871  &format_col, "col", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
872 
873  memset(cache->uv_layer_names, 0, sizeof(cache->uv_layer_names));
874 
875  /* Strand Data */
876  cache->proc_strand_buf = GPU_vertbuf_create_with_format(&format_data);
878  GPU_vertbuf_attr_get_raw_data(cache->proc_strand_buf, data_id, &data_step);
879 
882  GPU_vertbuf_attr_get_raw_data(cache->proc_strand_seg_buf, seg_id, &seg_step);
883 
884  /* UV layers */
885  for (int i = 0; i < cache->num_uv_layers; i++) {
886  cache->proc_uv_buf[i] = GPU_vertbuf_create_with_format(&format_uv);
888  GPU_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]);
889 
890  char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
891  const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
893 
894  int n = 0;
895  BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%s", attr_safe_name);
896 
897  if (i == active_uv) {
898  BLI_strncpy(cache->uv_layer_names[i][n++], "au", MAX_LAYER_NAME_LEN);
899  }
900  if (i == render_uv) {
901  BLI_strncpy(cache->uv_layer_names[i][n++], "a", MAX_LAYER_NAME_LEN);
902  }
903  }
904 
905  MEM_SAFE_FREE(cache->proc_col_buf);
906  MEM_SAFE_FREE(cache->col_tex);
908 
909  cache->proc_col_buf = MEM_calloc_arrayN(cache->num_col_layers, sizeof(void *), "proc_col_buf");
910  cache->col_tex = MEM_calloc_arrayN(cache->num_col_layers, sizeof(void *), "col_tex");
912  cache->num_col_layers, sizeof(*cache->col_layer_names), "col_layer_names");
913 
914  /* Vertex colors */
915  for (int i = 0; i < cache->num_col_layers; i++) {
916  cache->proc_col_buf[i] = GPU_vertbuf_create_with_format(&format_col);
918  GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]);
919 
920  char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
921  const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR, i);
923 
924  int n = 0;
925  BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%s", attr_safe_name);
926 
927  if (i == active_col) {
928  BLI_strncpy(cache->col_layer_names[i][n++], "ac", MAX_LAYER_NAME_LEN);
929  }
930  if (i == render_col) {
931  BLI_strncpy(cache->col_layer_names[i][n++], "c", MAX_LAYER_NAME_LEN);
932  }
933  }
934 
935  if (cache->num_uv_layers || cache->num_col_layers) {
937  if (cache->num_uv_layers) {
938  for (int j = 0; j < cache->num_uv_layers; j++) {
939  mtfaces[j] = (const MTFace *)CustomData_get_layer_n(
940  &psmd->mesh_final->fdata, CD_MTFACE, j);
941  }
942  }
943  if (cache->num_col_layers) {
944  for (int j = 0; j < cache->num_col_layers; j++) {
945  mcols[j] = (const MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j);
946  }
947  }
948  }
949 
950  if (edit != NULL && edit->pathcache != NULL) {
952  psmd,
953  edit->pathcache,
955  0,
956  edit->totcached,
957  &data_step,
958  &seg_step,
959  &parent_uvs,
960  uv_step,
961  mtfaces,
962  cache->num_uv_layers,
963  &parent_mcol,
964  col_step,
965  mcols,
966  cache->num_col_layers);
967  }
968  else {
969  int curr_point = 0;
970  if ((psys->pathcache != NULL) &&
971  (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
972  curr_point = particle_batch_cache_fill_strands_data(psys,
973  psmd,
974  psys->pathcache,
976  0,
977  psys->totpart,
978  &data_step,
979  &seg_step,
980  &parent_uvs,
981  uv_step,
982  mtfaces,
983  cache->num_uv_layers,
984  &parent_mcol,
985  col_step,
986  mcols,
987  cache->num_col_layers);
988  }
989  if (psys->childcache) {
990  const int child_count = psys->totchild * psys->part->disp / 100;
991  curr_point = particle_batch_cache_fill_strands_data(psys,
992  psmd,
993  psys->childcache,
995  curr_point,
996  child_count,
997  &data_step,
998  &seg_step,
999  &parent_uvs,
1000  uv_step,
1001  mtfaces,
1002  cache->num_uv_layers,
1003  &parent_mcol,
1004  col_step,
1005  mcols,
1006  cache->num_col_layers);
1007  }
1008  }
1009  /* Cleanup. */
1010  if (parent_uvs != NULL) {
1011  /* TODO(sergey): For edit mode it should be edit->totcached. */
1012  for (int i = 0; i < psys->totpart; i++) {
1013  MEM_SAFE_FREE(parent_uvs[i]);
1014  }
1015  MEM_freeN(parent_uvs);
1016  }
1017  if (parent_mcol != NULL) {
1018  for (int i = 0; i < psys->totpart; i++) {
1019  MEM_SAFE_FREE(parent_mcol[i]);
1020  }
1021  MEM_freeN(parent_mcol);
1022  }
1023 
1024  /* Create vbo immediately to bind to texture buffer. */
1026  cache->strand_tex = GPU_texture_create_from_vertbuf("part_strand", cache->proc_strand_buf);
1027 
1029  cache->strand_seg_tex = GPU_texture_create_from_vertbuf("part_strand_seg",
1030  cache->proc_strand_seg_buf);
1031 
1032  for (int i = 0; i < cache->num_uv_layers; i++) {
1033  GPU_vertbuf_use(cache->proc_uv_buf[i]);
1034  cache->uv_tex[i] = GPU_texture_create_from_vertbuf("part_uv", cache->proc_uv_buf[i]);
1035  }
1036  for (int i = 0; i < cache->num_col_layers; i++) {
1037  GPU_vertbuf_use(cache->proc_col_buf[i]);
1038  cache->col_tex[i] = GPU_texture_create_from_vertbuf("part_col", cache->proc_col_buf[i]);
1039  }
1040 }
1041 
1043  ParticleSystem *psys,
1044  ParticleHairCache *cache,
1045  int thickness_res,
1046  int subdiv)
1047 {
1048  BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
1049 
1050  if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) {
1051  return;
1052  }
1053 
1054  int verts_per_hair = cache->final[subdiv].strands_res * thickness_res;
1055  /* +1 for primitive restart */
1056  int element_count = (verts_per_hair + 1) * cache->strands_len;
1057  GPUPrimType prim_type = (thickness_res == 1) ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP;
1058 
1059  static GPUVertFormat format = {0};
1061 
1062  /* initialize vertex format */
1064 
1066  GPU_vertbuf_data_alloc(vbo, 1);
1067 
1068  GPUIndexBufBuilder elb;
1069  GPU_indexbuf_init_ex(&elb, prim_type, element_count, element_count);
1070 
1071  if (edit != NULL && edit->pathcache != NULL) {
1073  edit->pathcache, 0, edit->totcached, verts_per_hair, &elb);
1074  }
1075  else {
1076  int curr_point = 0;
1077  if ((psys->pathcache != NULL) &&
1078  (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
1080  psys->pathcache, 0, psys->totpart, verts_per_hair, &elb);
1081  }
1082  if (psys->childcache) {
1083  const int child_count = psys->totchild * psys->part->disp / 100;
1085  psys->childcache, curr_point, child_count, verts_per_hair, &elb);
1086  }
1087  }
1088 
1089  cache->final[subdiv].proc_hairs[thickness_res - 1] = GPU_batch_create_ex(
1091 }
1092 
1094  ParticleSystem *psys,
1095  ParticleHairCache *cache,
1096  GPUMaterial *gpu_material)
1097 {
1098  if (cache->proc_point_buf == NULL) {
1099  /* initialize vertex format */
1100  GPUVertFormat pos_format = {0};
1101  uint pos_id = GPU_vertformat_attr_add(
1102  &pos_format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1103 
1104  cache->proc_point_buf = GPU_vertbuf_create_with_format(&pos_format);
1106 
1107  GPUVertBufRaw pos_step;
1108  GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step);
1109 
1110  GPUVertFormat length_format = {0};
1111  uint length_id = GPU_vertformat_attr_add(
1112  &length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
1113 
1114  cache->proc_length_buf = GPU_vertbuf_create_with_format(&length_format);
1116 
1117  GPUVertBufRaw length_step;
1118  GPU_vertbuf_attr_get_raw_data(cache->proc_length_buf, length_id, &length_step);
1119 
1120  if (edit != NULL && edit->pathcache != NULL) {
1122  edit->pathcache, edit->totcached, &pos_step, &length_step);
1123  }
1124  else {
1125  if ((psys->pathcache != NULL) &&
1126  (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
1128  psys->pathcache, psys->totpart, &pos_step, &length_step);
1129  }
1130  if (psys->childcache) {
1131  const int child_count = psys->totchild * psys->part->disp / 100;
1133  psys->childcache, child_count, &pos_step, &length_step);
1134  }
1135  }
1136 
1137  /* Create vbo immediately to bind to texture buffer. */
1139  cache->point_tex = GPU_texture_create_from_vertbuf("part_point", cache->proc_point_buf);
1140  }
1141 
1142  /* Checking hair length separately, only allocating gpu memory when needed. */
1143  if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex == NULL) {
1144  ListBase gpu_attrs = GPU_material_attributes(gpu_material);
1145  LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) {
1146  if (attr->type == CD_HAIRLENGTH) {
1148  cache->length_tex = GPU_texture_create_from_vertbuf("hair_length", cache->proc_length_buf);
1149  break;
1150  }
1151  }
1152  }
1153 }
1154 
1156  ParticleSystem *psys,
1157  ModifierData *md,
1158  ParticleHairCache *hair_cache)
1159 {
1160  if (hair_cache->pos != NULL && hair_cache->indices != NULL) {
1161  return;
1162  }
1163 
1164  int curr_point = 0;
1166 
1167  GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
1168  GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
1169 
1170  static GPUVertFormat format = {0};
1172  uint *uv_id = NULL;
1173  uint *col_id = NULL;
1174  int num_uv_layers = 0;
1175  int num_col_layers = 0;
1176  int active_uv = 0;
1177  int active_col = 0;
1178  const MTFace **mtfaces = NULL;
1179  const MCol **mcols = NULL;
1180  float(**parent_uvs)[2] = NULL;
1181  MCol **parent_mcol = NULL;
1182 
1183  if (psmd != NULL) {
1185  num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV);
1187  }
1191  }
1192  }
1193 
1195 
1196  /* initialize vertex format */
1200 
1201  if (psmd) {
1202  uv_id = MEM_mallocN(sizeof(*uv_id) * num_uv_layers, "UV attr format");
1203  col_id = MEM_mallocN(sizeof(*col_id) * num_col_layers, "Col attr format");
1204 
1205  for (int i = 0; i < num_uv_layers; i++) {
1206 
1207  char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
1208  const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
1210 
1211  BLI_snprintf(uuid, sizeof(uuid), "a%s", attr_safe_name);
1213 
1214  if (i == active_uv) {
1216  }
1217  }
1218 
1219  for (int i = 0; i < num_col_layers; i++) {
1220  char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
1221  const char *name = CustomData_get_layer_name(
1222  &psmd->mesh_final->ldata, CD_PROP_BYTE_COLOR, i);
1224 
1225  BLI_snprintf(uuid, sizeof(uuid), "a%s", attr_safe_name);
1227 
1228  if (i == active_col) {
1230  }
1231  }
1232  }
1233 
1234  hair_cache->pos = GPU_vertbuf_create_with_format(&format);
1235  GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len);
1236 
1237  GPUIndexBufBuilder elb;
1238  GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len);
1239 
1240  if (num_uv_layers || num_col_layers) {
1242  if (num_uv_layers) {
1243  mtfaces = MEM_mallocN(sizeof(*mtfaces) * num_uv_layers, "Faces UV layers");
1244  for (int i = 0; i < num_uv_layers; i++) {
1245  mtfaces[i] = (const MTFace *)CustomData_get_layer_n(
1246  &psmd->mesh_final->fdata, CD_MTFACE, i);
1247  }
1248  }
1249  if (num_col_layers) {
1250  mcols = MEM_mallocN(sizeof(*mcols) * num_col_layers, "Color layers");
1251  for (int i = 0; i < num_col_layers; i++) {
1252  mcols[i] = (const MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, i);
1253  }
1254  }
1255  }
1256 
1257  if (edit != NULL && edit->pathcache != NULL) {
1258  curr_point = particle_batch_cache_fill_segments(psys,
1259  psmd,
1260  edit->pathcache,
1262  0,
1263  0,
1264  edit->totcached,
1265  num_uv_layers,
1266  num_col_layers,
1267  mtfaces,
1268  mcols,
1269  uv_id,
1270  col_id,
1271  &parent_uvs,
1272  &parent_mcol,
1273  &elb,
1274  &attr_id,
1275  hair_cache);
1276  }
1277  else {
1278  if ((psys->pathcache != NULL) &&
1279  (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
1280  curr_point = particle_batch_cache_fill_segments(psys,
1281  psmd,
1282  psys->pathcache,
1284  0,
1285  0,
1286  psys->totpart,
1287  num_uv_layers,
1288  num_col_layers,
1289  mtfaces,
1290  mcols,
1291  uv_id,
1292  col_id,
1293  &parent_uvs,
1294  &parent_mcol,
1295  &elb,
1296  &attr_id,
1297  hair_cache);
1298  }
1299  if (psys->childcache != NULL) {
1300  const int child_count = psys->totchild * psys->part->disp / 100;
1301  curr_point = particle_batch_cache_fill_segments(psys,
1302  psmd,
1303  psys->childcache,
1305  psys->totpart,
1306  curr_point,
1307  child_count,
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  }
1321  /* Cleanup. */
1322  if (parent_uvs != NULL) {
1323  /* TODO(sergey): For edit mode it should be edit->totcached. */
1324  for (int i = 0; i < psys->totpart; i++) {
1325  MEM_SAFE_FREE(parent_uvs[i]);
1326  }
1327  MEM_freeN(parent_uvs);
1328  }
1329  if (parent_mcol != NULL) {
1330  for (int i = 0; i < psys->totpart; i++) {
1331  MEM_SAFE_FREE(parent_mcol[i]);
1332  }
1333  MEM_freeN(parent_mcol);
1334  }
1335  if (num_uv_layers) {
1336  MEM_freeN((void *)mtfaces);
1337  }
1338  if (num_col_layers) {
1339  MEM_freeN((void *)mcols);
1340  }
1341  if (psmd != NULL) {
1342  MEM_freeN(uv_id);
1343  }
1344  hair_cache->indices = GPU_indexbuf_build(&elb);
1345 }
1346 
1348  ParticleSystem *psys,
1349  ParticlePointCache *point_cache)
1350 {
1351  if (point_cache->pos != NULL) {
1352  return;
1353  }
1354 
1355  static GPUVertFormat format = {0};
1356  static uint pos_id, rot_id, val_id;
1357  int i, curr_point;
1358  ParticleData *pa;
1360  ParticleSimulationData sim = {NULL};
1361  const DRWContextState *draw_ctx = DRW_context_state_get();
1362 
1363  sim.depsgraph = draw_ctx->depsgraph;
1364  sim.scene = draw_ctx->scene;
1365  sim.ob = object;
1366  sim.psys = psys;
1367  sim.psmd = psys_get_modifier(object, psys);
1368  psys_sim_data_init(&sim);
1369 
1370  GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
1371 
1372  if (format.attr_len == 0) {
1373  /* initialize vertex format */
1374  pos_id = GPU_vertformat_attr_add(&format, "part_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1375  val_id = GPU_vertformat_attr_add(&format, "part_val", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
1376  rot_id = GPU_vertformat_attr_add(&format, "part_rot", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1377  }
1378 
1379  point_cache->pos = GPU_vertbuf_create_with_format(&format);
1380  GPU_vertbuf_data_alloc(point_cache->pos, psys->totpart);
1381 
1382  for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
1383  state.time = DEG_get_ctime(draw_ctx->depsgraph);
1384  if (!psys_get_particle_state(&sim, i, &state, 0)) {
1385  continue;
1386  }
1387 
1388  float val;
1389 
1390  GPU_vertbuf_attr_set(point_cache->pos, pos_id, curr_point, state.co);
1391  GPU_vertbuf_attr_set(point_cache->pos, rot_id, curr_point, state.rot);
1392 
1393  switch (psys->part->draw_col) {
1394  case PART_DRAW_COL_VEL:
1395  val = len_v3(state.vel) / psys->part->color_vec_max;
1396  break;
1397  case PART_DRAW_COL_ACC:
1398  val = len_v3v3(state.vel, pa->prev_state.vel) /
1399  ((state.time - pa->prev_state.time) * psys->part->color_vec_max);
1400  break;
1401  default:
1402  val = -1.0f;
1403  break;
1404  }
1405 
1406  GPU_vertbuf_attr_set(point_cache->pos, val_id, curr_point, &val);
1407 
1408  curr_point++;
1409  }
1410 
1411  if (curr_point != psys->totpart) {
1412  GPU_vertbuf_data_resize(point_cache->pos, curr_point);
1413  }
1414 
1415  psys_sim_data_free(&sim);
1416 }
1417 
1418 static void drw_particle_update_ptcache_edit(Object *object_eval,
1419  ParticleSystem *psys,
1420  PTCacheEdit *edit)
1421 {
1422  if (edit->psys == NULL) {
1423  return;
1424  }
1425  /* NOTE: Get flag from particle system coming from drawing object.
1426  * this is where depsgraph will be setting flags to.
1427  */
1428  const DRWContextState *draw_ctx = DRW_context_state_get();
1429  Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
1430  Object *object_orig = DEG_get_original_object(object_eval);
1431  if (psys->flag & PSYS_HAIR_UPDATED) {
1432  PE_update_object(draw_ctx->depsgraph, scene_orig, object_orig, 0);
1433  psys->flag &= ~PSYS_HAIR_UPDATED;
1434  }
1435  if (edit->pathcache == NULL) {
1436  Depsgraph *depsgraph = draw_ctx->depsgraph;
1438  scene_orig,
1439  object_orig,
1440  edit,
1443  }
1444 }
1445 
1446 static void drw_particle_update_ptcache(Object *object_eval, ParticleSystem *psys)
1447 {
1448  if ((object_eval->mode & OB_MODE_PARTICLE_EDIT) == 0) {
1449  return;
1450  }
1451  const DRWContextState *draw_ctx = DRW_context_state_get();
1452  Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
1453  Object *object_orig = DEG_get_original_object(object_eval);
1454  PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, object_orig);
1455  if (edit != NULL) {
1456  drw_particle_update_ptcache_edit(object_eval, psys, edit);
1457  }
1458 }
1459 
1460 typedef struct ParticleDrawSource {
1466 
1468  ParticleSystem *psys,
1469  ModifierData *md,
1470  PTCacheEdit *edit,
1471  ParticleDrawSource *r_draw_source)
1472 {
1473  const DRWContextState *draw_ctx = DRW_context_state_get();
1474  r_draw_source->object = object;
1475  r_draw_source->psys = psys;
1476  r_draw_source->md = md;
1477  r_draw_source->edit = edit;
1478  if (psys_in_edit_mode(draw_ctx->depsgraph, psys)) {
1479  r_draw_source->object = DEG_get_original_object(object);
1480  r_draw_source->psys = psys_orig_get(psys);
1481  }
1482 }
1483 
1485  ParticleSystem *psys,
1486  ModifierData *md)
1487 {
1489  if (cache->hair.hairs == NULL) {
1490  drw_particle_update_ptcache(object, psys);
1491  ParticleDrawSource source;
1492  drw_particle_get_hair_source(object, psys, md, NULL, &source);
1493  ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
1494  particle_batch_cache_ensure_pos_and_seg(source.edit, source.psys, source.md, &cache->hair);
1495  cache->hair.hairs = GPU_batch_create(
1496  GPU_PRIM_LINE_STRIP, cache->hair.pos, cache->hair.indices);
1497  }
1498  return cache->hair.hairs;
1499 }
1500 
1502 {
1504 
1505  if (cache->point.points == NULL) {
1506  particle_batch_cache_ensure_pos(object, psys, &cache->point);
1508  }
1509 
1510  return cache->point.points;
1511 }
1512 
1514  ParticleSystem *psys,
1515  ModifierData *UNUSED(md),
1516  ParticleHairCache *hair_cache,
1517  bool use_weight)
1518 {
1519  if (hair_cache->pos != NULL && hair_cache->indices != NULL) {
1520  return;
1521  }
1522 
1523  ParticleData *particle = (use_weight) ? psys->particles : NULL;
1524 
1525  GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
1526  GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
1527 
1528  GPUVertBufRaw data_step;
1529  GPUIndexBufBuilder elb;
1530  uint pos_id, color_id;
1531  GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
1532 
1533  hair_cache->pos = GPU_vertbuf_create_with_format(edit_point_format);
1534  GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len);
1535  GPU_vertbuf_attr_get_raw_data(hair_cache->pos, pos_id, &data_step);
1536 
1537  GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len);
1538 
1539  if (edit != NULL && edit->pathcache != NULL) {
1541  edit, particle, edit->pathcache, 0, edit->totcached, &elb, &data_step);
1542  }
1543  else {
1544  BLI_assert_msg(0, "Hairs are not in edit mode!");
1545  }
1546  hair_cache->indices = GPU_indexbuf_build(&elb);
1547 }
1548 
1550  ParticleSystem *psys,
1551  PTCacheEdit *edit,
1552  bool use_weight)
1553 {
1555  if (cache->edit_is_weight != use_weight) {
1558  }
1559  if (cache->edit_hair.hairs != NULL) {
1560  return cache->edit_hair.hairs;
1561  }
1562  drw_particle_update_ptcache_edit(object, psys, edit);
1563  ensure_seg_pt_count(edit, psys, &cache->edit_hair);
1564  particle_batch_cache_ensure_edit_pos_and_seg(edit, psys, NULL, &cache->edit_hair, use_weight);
1565  cache->edit_hair.hairs = GPU_batch_create(
1567  cache->edit_is_weight = use_weight;
1568  return cache->edit_hair.hairs;
1569 }
1570 
1572 {
1573  if (cache->edit_inner_pos != NULL) {
1574  return;
1575  }
1576  cache->edit_inner_point_len = 0;
1577  for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1578  const PTCacheEditPoint *point = &edit->points[point_index];
1579  if (point->flag & PEP_HIDE) {
1580  continue;
1581  }
1582  BLI_assert(point->totkey >= 1);
1583  cache->edit_inner_point_len += (point->totkey - 1);
1584  }
1585 }
1586 
1588  ParticleBatchCache *cache)
1589 {
1590  if (cache->edit_inner_pos != NULL) {
1591  return;
1592  }
1593 
1594  uint pos_id, color_id;
1595  GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
1596 
1597  cache->edit_inner_pos = GPU_vertbuf_create_with_format(edit_point_format);
1599 
1600  int global_key_index = 0;
1601  for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1602  const PTCacheEditPoint *point = &edit->points[point_index];
1603  if (point->flag & PEP_HIDE) {
1604  continue;
1605  }
1606  for (int key_index = 0; key_index < point->totkey - 1; key_index++) {
1607  PTCacheEditKey *key = &point->keys[key_index];
1608  float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
1609  GPU_vertbuf_attr_set(cache->edit_inner_pos, pos_id, global_key_index, key->world_co);
1610  GPU_vertbuf_attr_set(cache->edit_inner_pos, color_id, global_key_index, &color);
1611  global_key_index++;
1612  }
1613  }
1614 }
1615 
1617  ParticleSystem *psys,
1618  PTCacheEdit *edit)
1619 {
1621  if (cache->edit_inner_points != NULL) {
1622  return cache->edit_inner_points;
1623  }
1624  drw_particle_update_ptcache_edit(object, psys, edit);
1625  ensure_edit_inner_points_count(edit, cache);
1628  return cache->edit_inner_points;
1629 }
1630 
1632 {
1633  if (cache->edit_tip_pos != NULL) {
1634  return;
1635  }
1636  cache->edit_tip_point_len = 0;
1637  for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1638  const PTCacheEditPoint *point = &edit->points[point_index];
1639  if (point->flag & PEP_HIDE) {
1640  continue;
1641  }
1642  cache->edit_tip_point_len += 1;
1643  }
1644 }
1645 
1647 {
1648  if (cache->edit_tip_pos != NULL) {
1649  return;
1650  }
1651 
1652  uint pos_id, color_id;
1653  GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
1654 
1655  cache->edit_tip_pos = GPU_vertbuf_create_with_format(edit_point_format);
1657 
1658  int global_point_index = 0;
1659  for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1660  const PTCacheEditPoint *point = &edit->points[point_index];
1661  if (point->flag & PEP_HIDE) {
1662  continue;
1663  }
1664  PTCacheEditKey *key = &point->keys[point->totkey - 1];
1665  float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
1666 
1667  GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, global_point_index, key->world_co);
1668  GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, global_point_index, &color);
1669  global_point_index++;
1670  }
1671 }
1672 
1674  ParticleSystem *psys,
1675  PTCacheEdit *edit)
1676 {
1678  if (cache->edit_tip_points != NULL) {
1679  return cache->edit_tip_points;
1680  }
1681  drw_particle_update_ptcache_edit(object, psys, edit);
1682  ensure_edit_tip_points_count(edit, cache);
1685  return cache->edit_tip_points;
1686 }
1687 
1689  ParticleSystem *psys,
1690  ModifierData *md,
1691  ParticleHairCache **r_hair_cache,
1692  GPUMaterial *gpu_material,
1693  int subdiv,
1694  int thickness_res)
1695 {
1696  bool need_ft_update = false;
1697 
1698  drw_particle_update_ptcache(object, psys);
1699 
1700  ParticleDrawSource source;
1701  drw_particle_get_hair_source(object, psys, md, NULL, &source);
1702 
1703  ParticleSettings *part = source.psys->part;
1705  *r_hair_cache = &cache->hair;
1706 
1707  (*r_hair_cache)->final[subdiv].strands_res = 1 << (part->draw_step + subdiv);
1708 
1709  /* Refreshed on combing and simulation. */
1710  if ((*r_hair_cache)->proc_point_buf == NULL ||
1711  (gpu_material && (*r_hair_cache)->length_tex == NULL)) {
1712  ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
1714  source.edit, source.psys, &cache->hair, gpu_material);
1715  need_ft_update = true;
1716  }
1717 
1718  /* Refreshed if active layer or custom data changes. */
1719  if ((*r_hair_cache)->strand_tex == NULL) {
1721  source.edit, source.psys, source.md, &cache->hair);
1722  }
1723 
1724  /* Refreshed only on subdiv count change. */
1725  if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) {
1727  need_ft_update = true;
1728  }
1729  if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) {
1731  source.edit, source.psys, &cache->hair, thickness_res, subdiv);
1732  }
1733 
1734  return need_ft_update;
1735 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
const char * CustomData_get_layer_name(const struct CustomData *data, int type, int n)
int CustomData_number_of_layers(const struct CustomData *data, int type)
bool CustomData_has_layer(const struct CustomData *data, int type)
int CustomData_get_active_layer(const struct CustomData *data, int type)
void * CustomData_get_layer_n(const struct CustomData *data, int type, int n)
int CustomData_get_render_layer(const struct CustomData *data, int type)
void BKE_mesh_tessface_ensure(struct Mesh *mesh)
#define DMCACHE_NOTFOUND
Definition: BKE_particle.h:672
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.c:3711
struct ParticleSystem * psys_orig_get(struct ParticleSystem *psys)
Definition: particle.c:753
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.c:726
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition: particle.c:2230
@ BKE_PARTICLE_BATCH_DIRTY_ALL
Definition: BKE_particle.h:686
#define DMCACHE_ISCHILD
Definition: BKE_particle.h:673
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.c:685
bool psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, bool always)
Definition: particle.c:4884
#define PEP_HIDE
#define PEK_SELECT
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
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
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:67
unsigned short ushort
Definition: BLI_sys_types.h:68
#define UNUSED(x)
#define ELEM(...)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
@ DAG_EVAL_RENDER
Definition: DEG_depsgraph.h:46
float DEG_get_ctime(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
struct Object * DEG_get_original_object(struct Object *object)
struct ID * DEG_get_original_id(struct ID *id)
@ CD_PROP_BYTE_COLOR
@ CD_MTFACE
@ CD_HAIRLENGTH
@ CD_MLOOPUV
#define MAX_MTFACE
@ OB_MODE_PARTICLE_EDIT
#define PART_FROM_VOLUME
#define PART_FROM_FACE
#define PART_CHILD_PARTICLES
@ PART_DRAW_PARENT
#define PART_DRAW_COL_ACC
#define PART_DRAW_COL_VEL
#define PSYS_HAIR_UPDATED
#define DRW_TEXTURE_FREE_SAFE(tex)
Definition: DRW_render.h:183
struct PTCacheEdit * PE_create_current(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob)
void PE_update_object(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, int useflag)
GPUBatch
Definition: GPU_batch.h:78
#define GPU_batch_create(prim, verts, elem)
Definition: GPU_batch.h:95
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition: GPU_batch.h:216
GPUBatch * GPU_batch_create_ex(GPUPrimType prim, GPUVertBuf *vert, GPUIndexBuf *elem, eGPUBatchFlag owns_flag)
Definition: gpu_batch.cc:43
@ GPU_BATCH_OWNS_INDEX
Definition: GPU_batch.h:39
@ GPU_BATCH_OWNS_VBO
Definition: GPU_batch.h:30
#define GPU_INDEXBUF_DISCARD_SAFE(elem)
void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *)
GPUIndexBuf * 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)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
ListBase GPU_material_attributes(GPUMaterial *material)
Definition: gpu_material.c:216
GPUPrimType
Definition: GPU_primitive.h:18
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:19
@ GPU_PRIM_LINE_STRIP
Definition: GPU_primitive.h:22
@ GPU_PRIM_TRI_STRIP
Definition: GPU_primitive.h:24
GPUTexture * GPU_texture_create_from_vertbuf(const char *name, struct GPUVertBuf *vert)
Definition: gpu_texture.cc:361
#define GPU_vertbuf_create_with_format(format)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
void GPU_vertbuf_use(GPUVertBuf *)
GPU_INLINE void * GPU_vertbuf_raw_step(GPUVertBufRaw *a)
void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *, uint a_idx, GPUVertBufRaw *access)
void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data)
void GPU_vertbuf_data_resize(GPUVertBuf *, uint v_len)
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
@ GPU_COMP_U8
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
const Depsgraph * depsgraph
static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *cache, int thickness_res, int subdiv)
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_ensure_pos(Object *object, ParticleSystem *psys, ParticlePointCache *point_cache)
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)
static void particle_batch_cache_clear(ParticleSystem *psys)
struct EditStrandData EditStrandData
static void count_cache_segment_keys(ParticleCacheKey **pathcache, const int num_path_cache_keys, ParticleHairCache *hair_cache)
static void particle_pack_mcol(MCol *mcol, ushort r_scol[3])
static int particle_batch_cache_fill_segments_edit(const PTCacheEdit *UNUSED(edit), const ParticleData *particle, ParticleCacheKey **path_cache, const int start_index, const int num_path_keys, GPUIndexBufBuilder *elb, GPUVertBufRaw *attr_step)
static void particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit *edit, ParticleBatchCache *cache)
GPUBatch * DRW_particles_batch_cache_get_edit_strands(Object *object, ParticleSystem *psys, PTCacheEdit *edit, bool use_weight)
static void particle_batch_cache_init(ParticleSystem *psys)
static void particle_batch_cache_clear_point(ParticlePointCache *point_cache)
struct ParticleDrawSource ParticleDrawSource
GPUBatch * DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *psys)
static float particle_key_weight(const ParticleData *particle, int strand, float t)
static ParticleBatchCache * particle_batch_cache_get(ParticleSystem *psys)
static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *cache, GPUMaterial *gpu_material)
static void ensure_edit_tip_points_count(const PTCacheEdit *edit, ParticleBatchCache *cache)
GPUBatch * DRW_particles_batch_cache_get_edit_inner_points(Object *object, ParticleSystem *psys, PTCacheEdit *edit)
GPUBatch * DRW_particles_batch_cache_get_edit_tip_points(Object *object, ParticleSystem *psys, PTCacheEdit *edit)
static void ensure_edit_inner_points_count(const PTCacheEdit *edit, ParticleBatchCache *cache)
struct HairAttributeID HairAttributeID
static void drw_particle_get_hair_source(Object *object, ParticleSystem *psys, ModifierData *md, PTCacheEdit *edit, ParticleDrawSource *r_draw_source)
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_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit, ParticleSystem *psys, ModifierData *md, ParticleHairCache *hair_cache)
static GPUVertFormat * edit_points_vert_format_get(uint *r_pos_id, uint *r_color_id)
GPUBatch * DRW_particles_batch_cache_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
void DRW_particle_batch_cache_free(ParticleSystem *psys)
static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit, ParticleSystem *psys, ModifierData *md, ParticleHairCache *cache)
static void drw_particle_update_ptcache(Object *object_eval, 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_indices(ParticleCacheKey **path_cache, const int start_index, const int num_path_keys, const int res, GPUIndexBufBuilder *elb)
static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache, int subdiv)
static bool particle_batch_cache_valid(ParticleSystem *psys)
static void drw_particle_update_ptcache_edit(Object *object_eval, ParticleSystem *psys, PTCacheEdit *edit)
static void particle_batch_cache_ensure_edit_pos_and_seg(PTCacheEdit *edit, ParticleSystem *psys, ModifierData *UNUSED(md), ParticleHairCache *hair_cache, bool use_weight)
static void particle_batch_cache_free_hair(ParticleHairCache *hair)
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 particle_calculate_parent_mcol(ParticleSystem *psys, ParticleSystemModifierData *psmd, const int num_col_layers, const int parent_index, const MCol **mcols, MCol *r_mcol)
bool particles_ensure_procedural_data(Object *object, ParticleSystem *psys, ModifierData *md, ParticleHairCache **r_hair_cache, GPUMaterial *gpu_material, int subdiv, int thickness_res)
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 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)
static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
static void ensure_seg_pt_count(PTCacheEdit *edit, ParticleSystem *psys, ParticleHairCache *hair_cache)
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])
struct ParticlePointCache ParticlePointCache
struct ParticleBatchCache ParticleBatchCache
void DRW_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode)
@ PARTICLE_SOURCE_CHILDREN
@ PARTICLE_SOURCE_PARENT
static void particle_batch_cache_ensure_edit_inner_pos(PTCacheEdit *edit, ParticleBatchCache *cache)
#define MAX_THICKRES
#define MAX_HAIR_SUBDIV
#define MAX_LAYER_NAME_LEN
const DRWContextState * DRW_context_state_get(void)
struct @653::@656 attr_id
const int state
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
MINLINE unsigned short unit_float_to_ushort_clamp(float val)
float BLI_color_from_srgb_table[256]
Definition: math_color.c:517
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)
Definition: math_float2.h:232
#define floorf(x)
Definition: metal/compat.h:224
static bool is_child(const Object *ob, const Object *parent)
struct Scene * scene
Definition: DRW_render.h:979
struct Depsgraph * depsgraph
Definition: DRW_render.h:987
unsigned char r
unsigned char g
unsigned char b
unsigned int v4
int totface
CustomData fdata
struct MFace * mface
CustomData ldata
struct ParticleCacheKey ** pathcache
PTCacheEditPoint * points
struct ParticleSystem * psys
ParticleKey prev_state
GPUTexture ** col_tex
GPUVertBuf * proc_point_buf
GPUTexture * uv_tex[MAX_MTFACE]
GPUVertBuf * proc_strand_buf
GPUVertBuf ** proc_col_buf
GPUIndexBuf * indices
GPUTexture * length_tex
char uv_layer_names[MAX_MTFACE][MAX_LAYER_NAME_CT][MAX_LAYER_NAME_LEN]
GPUVertBuf * proc_length_buf
GPUTexture * strand_seg_tex
GPUVertBuf * proc_strand_seg_buf
GPUTexture * point_tex
GPUTexture * strand_tex
GPUVertBuf * proc_uv_buf[MAX_MTFACE]
ParticleHairFinalCache final[MAX_HAIR_SUBDIV]
char(* col_layer_names)[MAX_LAYER_NAME_CT][MAX_LAYER_NAME_LEN]
GPUBatch * proc_hairs[MAX_THICKRES]
struct Depsgraph * depsgraph
Definition: BKE_particle.h:69
struct ParticleSystemModifierData * psmd
Definition: BKE_particle.h:73
struct Scene * scene
Definition: BKE_particle.h:70
struct ParticleSystem * psys
Definition: BKE_particle.h:72
struct Object * ob
Definition: BKE_particle.h:71
struct ParticleSystem * psys
ChildParticle * child
ParticleData * particles
ParticleSettings * part
struct ParticleCacheKey ** childcache
struct ParticleCacheKey ** pathcache