1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2017 by Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup draw
22  *
23  * \brief Particle API for render engines
24  */
25 
26 #include "DRW_render.h"
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "BLI_ghash.h"
31 #include "BLI_math_vector.h"
32 #include "BLI_string.h"
33 #include "BLI_utildefines.h"
34 
35 #include "DNA_customdata_types.h"
36 #include "DNA_mesh_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_modifier_types.h"
39 #include "DNA_particle_types.h"
40 
41 #include "BKE_mesh.h"
42 #include "BKE_particle.h"
43 #include "BKE_pointcache.h"
44 
45 #include "ED_particle.h"
46 
47 #include "GPU_batch.h"
48 
49 #include "DEG_depsgraph_query.h"
50 
51 #include "draw_cache_impl.h" /* own include */
52 #include "draw_hair_private.h"
53 
54 static void particle_batch_cache_clear(ParticleSystem *psys);
55 
56 /* ---------------------------------------------------------------------- */
57 /* Particle GPUBatch Cache */
58 
59 typedef struct ParticlePointCache {
60   GPUVertBuf *pos;
61   GPUBatch *points;
62   int elems_len;
63   int point_len;
64 } ParticlePointCache;
65 
66 typedef struct ParticleBatchCache {
67   /* Object mode strands for hair and points for particle,
68    * strands for paths when in edit mode.
69    */
70   ParticleHairCache hair;   /* Used for hair strands */
71   ParticlePointCache point; /* Used for particle points. */
72 
73   /* Control points when in edit mode. */
74   ParticleHairCache edit_hair;
75 
76   GPUVertBuf *edit_pos;
77   GPUBatch *edit_strands;
78 
79   GPUVertBuf *edit_inner_pos;
80   GPUBatch *edit_inner_points;
81   int edit_inner_point_len;
82 
83   GPUVertBuf *edit_tip_pos;
84   GPUBatch *edit_tip_points;
85   int edit_tip_point_len;
86 
87   /* Settings to determine if cache is invalid. */
88   bool is_dirty;
89   bool edit_is_weight;
90 } ParticleBatchCache;
91 
92 /* GPUBatch cache management. */
93 
94 typedef struct HairAttributeID {
95   uint pos;
96   uint tan;
97   uint ind;
98 } HairAttributeID;
99 
100 typedef struct EditStrandData {
101   float pos[3];
102   float color;
103 } EditStrandData;
104 
edit_points_vert_format_get(uint * r_pos_id,uint * r_color_id)105 static GPUVertFormat *edit_points_vert_format_get(uint *r_pos_id, uint *r_color_id)
106 {
107   static GPUVertFormat edit_point_format = {0};
108   static uint pos_id, color_id;
109   if (edit_point_format.attr_len == 0) {
110     /* Keep in sync with EditStrandData */
111     pos_id = GPU_vertformat_attr_add(&edit_point_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
112     color_id = GPU_vertformat_attr_add(
113         &edit_point_format, "color", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
114   }
115   *r_pos_id = pos_id;
116   *r_color_id = color_id;
117   return &edit_point_format;
118 }
119 
particle_batch_cache_valid(ParticleSystem * psys)120 static bool particle_batch_cache_valid(ParticleSystem *psys)
121 {
122   ParticleBatchCache *cache = psys->batch_cache;
123 
124   if (cache == NULL) {
125     return false;
126   }
127 
128   if (cache->is_dirty == false) {
129     return true;
130   }
131 
132   return false;
133 
134   return true;
135 }
136 
particle_batch_cache_init(ParticleSystem * psys)137 static void particle_batch_cache_init(ParticleSystem *psys)
138 {
139   ParticleBatchCache *cache = psys->batch_cache;
140 
141   if (!cache) {
142     cache = psys->batch_cache = MEM_callocN(sizeof(*cache), __func__);
143   }
144   else {
145     memset(cache, 0, sizeof(*cache));
146   }
147 
148   cache->is_dirty = false;
149 }
150 
particle_batch_cache_get(ParticleSystem * psys)151 static ParticleBatchCache *particle_batch_cache_get(ParticleSystem *psys)
152 {
153   if (!particle_batch_cache_valid(psys)) {
154     particle_batch_cache_clear(psys);
155     particle_batch_cache_init(psys);
156   }
157   return psys->batch_cache;
158 }
159 
DRW_particle_batch_cache_dirty_tag(ParticleSystem * psys,int mode)160 void DRW_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode)
161 {
162   ParticleBatchCache *cache = psys->batch_cache;
163   if (cache == NULL) {
164     return;
165   }
166   switch (mode) {
167     case BKE_PARTICLE_BATCH_DIRTY_ALL:
168       cache->is_dirty = true;
169       break;
170     default:
171       BLI_assert(0);
172   }
173 }
174 
particle_batch_cache_clear_point(ParticlePointCache * point_cache)175 static void particle_batch_cache_clear_point(ParticlePointCache *point_cache)
176 {
177   GPU_BATCH_DISCARD_SAFE(point_cache->points);
178   GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
179 }
180 
particle_batch_cache_clear_hair(ParticleHairCache * hair_cache)181 void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
182 {
183   /* TODO more granular update tagging. */
184   GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf);
185   DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex);
186 
187   GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf);
188   GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_seg_buf);
189   DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex);
190   DRW_TEXTURE_FREE_SAFE(hair_cache->strand_seg_tex);
191 
192   for (int i = 0; i < MAX_MTFACE; i++) {
193     GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]);
194     DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]);
195   }
196   for (int i = 0; i < MAX_MCOL; i++) {
197     GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]);
198     DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]);
199   }
200   for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
201     GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf);
202     DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex);
203     for (int j = 0; j < MAX_THICKRES; j++) {
204       GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]);
205     }
206   }
207 
208   /* "Normal" legacy hairs */
209   GPU_BATCH_DISCARD_SAFE(hair_cache->hairs);
210   GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
211   GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
212 }
213 
particle_batch_cache_clear(ParticleSystem * psys)214 static void particle_batch_cache_clear(ParticleSystem *psys)
215 {
216   ParticleBatchCache *cache = psys->batch_cache;
217   if (!cache) {
218     return;
219   }
220 
221   particle_batch_cache_clear_point(&cache->point);
222   particle_batch_cache_clear_hair(&cache->hair);
223 
224   particle_batch_cache_clear_hair(&cache->edit_hair);
225 
226   GPU_BATCH_DISCARD_SAFE(cache->edit_inner_points);
227   GPU_VERTBUF_DISCARD_SAFE(cache->edit_inner_pos);
228   GPU_BATCH_DISCARD_SAFE(cache->edit_tip_points);
229   GPU_VERTBUF_DISCARD_SAFE(cache->edit_tip_pos);
230 }
231 
DRW_particle_batch_cache_free(ParticleSystem * psys)232 void DRW_particle_batch_cache_free(ParticleSystem *psys)
233 {
234   particle_batch_cache_clear(psys);
235   MEM_SAFE_FREE(psys->batch_cache);
236 }
237 
count_cache_segment_keys(ParticleCacheKey ** pathcache,const int num_path_cache_keys,ParticleHairCache * hair_cache)238 static void count_cache_segment_keys(ParticleCacheKey **pathcache,
239                                      const int num_path_cache_keys,
240                                      ParticleHairCache *hair_cache)
241 {
242   for (int i = 0; i < num_path_cache_keys; i++) {
243     ParticleCacheKey *path = pathcache[i];
244     if (path->segments > 0) {
245       hair_cache->strands_len++;
246       hair_cache->elems_len += path->segments + 2;
247       hair_cache->point_len += path->segments + 1;
248     }
249   }
250 }
251 
ensure_seg_pt_count(PTCacheEdit * edit,ParticleSystem * psys,ParticleHairCache * hair_cache)252 static void ensure_seg_pt_count(PTCacheEdit *edit,
253                                 ParticleSystem *psys,
254                                 ParticleHairCache *hair_cache)
255 {
256   if ((hair_cache->pos != NULL && hair_cache->indices != NULL) ||
257       (hair_cache->proc_point_buf != NULL)) {
258     return;
259   }
260 
261   hair_cache->strands_len = 0;
262   hair_cache->elems_len = 0;
263   hair_cache->point_len = 0;
264 
265   if (edit != NULL && edit->pathcache != NULL) {
266     count_cache_segment_keys(edit->pathcache, edit->totcached, hair_cache);
267   }
268   else {
269     if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
270       count_cache_segment_keys(psys->pathcache, psys->totpart, hair_cache);
271     }
272     if (psys->childcache) {
273       const int child_count = psys->totchild * psys->part->disp / 100;
274       count_cache_segment_keys(psys->childcache, child_count, hair_cache);
275     }
276   }
277 }
278 
particle_pack_mcol(MCol * mcol,ushort r_scol[3])279 static void particle_pack_mcol(MCol *mcol, ushort r_scol[3])
280 {
281   /* Convert to linear ushort and swizzle */
282   r_scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
283   r_scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
284   r_scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
285 }
286 
287 /* Used by parent particles and simple children. */
particle_calculate_parent_uvs(ParticleSystem * psys,ParticleSystemModifierData * psmd,const int num_uv_layers,const int parent_index,MTFace ** mtfaces,float (* r_uv)[2])288 static void particle_calculate_parent_uvs(ParticleSystem *psys,
289                                           ParticleSystemModifierData *psmd,
290                                           const int num_uv_layers,
291                                           const int parent_index,
292                                           /*const*/ MTFace **mtfaces,
293                                           float (*r_uv)[2])
294 {
295   if (psmd == NULL) {
296     return;
297   }
298   const int emit_from = psmd->psys->part->from;
299   if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
300     return;
301   }
302   ParticleData *particle = &psys->particles[parent_index];
303   int num = particle->num_dmcache;
304   if (num == DMCACHE_NOTFOUND || num == DMCACHE_ISCHILD) {
305     if (particle->num < psmd->mesh_final->totface) {
306       num = particle->num;
307     }
308   }
309   if (num != DMCACHE_NOTFOUND && num != DMCACHE_ISCHILD) {
310     MFace *mface = &psmd->mesh_final->mface[num];
311     for (int j = 0; j < num_uv_layers; j++) {
312       psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]);
313     }
314   }
315 }
316 
particle_calculate_parent_mcol(ParticleSystem * psys,ParticleSystemModifierData * psmd,const int num_col_layers,const int parent_index,MCol ** mcols,MCol * r_mcol)317 static void particle_calculate_parent_mcol(ParticleSystem *psys,
318                                            ParticleSystemModifierData *psmd,
319                                            const int num_col_layers,
320                                            const int parent_index,
321                                            /*const*/ MCol **mcols,
322                                            MCol *r_mcol)
323 {
324   if (psmd == NULL) {
325     return;
326   }
327   const int emit_from = psmd->psys->part->from;
328   if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
329     return;
330   }
331   ParticleData *particle = &psys->particles[parent_index];
332   int num = particle->num_dmcache;
333   if (num == DMCACHE_NOTFOUND || num == DMCACHE_ISCHILD) {
334     if (particle->num < psmd->mesh_final->totface) {
335       num = particle->num;
336     }
337   }
338   if (num != DMCACHE_NOTFOUND && num != DMCACHE_ISCHILD) {
339     MFace *mface = &psmd->mesh_final->mface[num];
340     for (int j = 0; j < num_col_layers; j++) {
341       /* CustomDataLayer CD_MCOL has 4 structs per face. */
342       psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
343     }
344   }
345 }
346 
347 /* Used by interpolated children. */
particle_interpolate_children_uvs(ParticleSystem * psys,ParticleSystemModifierData * psmd,const int num_uv_layers,const int child_index,MTFace ** mtfaces,float (* r_uv)[2])348 static void particle_interpolate_children_uvs(ParticleSystem *psys,
349                                               ParticleSystemModifierData *psmd,
350                                               const int num_uv_layers,
351                                               const int child_index,
352                                               /*const*/ MTFace **mtfaces,
353                                               float (*r_uv)[2])
354 {
355   if (psmd == NULL) {
356     return;
357   }
358   const int emit_from = psmd->psys->part->from;
359   if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
360     return;
361   }
362   ChildParticle *particle = &psys->child[child_index];
363   int num = particle->num;
364   if (num != DMCACHE_NOTFOUND) {
365     MFace *mface = &psmd->mesh_final->mface[num];
366     for (int j = 0; j < num_uv_layers; j++) {
367       psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]);
368     }
369   }
370 }
371 
particle_interpolate_children_mcol(ParticleSystem * psys,ParticleSystemModifierData * psmd,const int num_col_layers,const int child_index,MCol ** mcols,MCol * r_mcol)372 static void particle_interpolate_children_mcol(ParticleSystem *psys,
373                                                ParticleSystemModifierData *psmd,
374                                                const int num_col_layers,
375                                                const int child_index,
376                                                /*const*/ MCol **mcols,
377                                                MCol *r_mcol)
378 {
379   if (psmd == NULL) {
380     return;
381   }
382   const int emit_from = psmd->psys->part->from;
383   if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) {
384     return;
385   }
386   ChildParticle *particle = &psys->child[child_index];
387   int num = particle->num;
388   if (num != DMCACHE_NOTFOUND) {
389     MFace *mface = &psmd->mesh_final->mface[num];
390     for (int j = 0; j < num_col_layers; j++) {
391       /* CustomDataLayer CD_MCOL has 4 structs per face. */
392       psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
393     }
394   }
395 }
396 
particle_calculate_uvs(ParticleSystem * psys,ParticleSystemModifierData * psmd,const bool is_simple,const int num_uv_layers,const int parent_index,const int child_index,MTFace ** mtfaces,float (** r_parent_uvs)[2],float (** r_uv)[2])397 static void particle_calculate_uvs(ParticleSystem *psys,
398                                    ParticleSystemModifierData *psmd,
399                                    const bool is_simple,
400                                    const int num_uv_layers,
401                                    const int parent_index,
402                                    const int child_index,
403                                    /*const*/ MTFace **mtfaces,
404                                    float (**r_parent_uvs)[2],
405                                    float (**r_uv)[2])
406 {
407   if (psmd == NULL) {
408     return;
409   }
410   if (is_simple) {
411     if (r_parent_uvs[parent_index] != NULL) {
412       *r_uv = r_parent_uvs[parent_index];
413     }
414     else {
415       *r_uv = MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs");
416     }
417   }
418   else {
419     *r_uv = MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs");
420   }
421   if (child_index == -1) {
422     /* Calculate UVs for parent particles. */
423     if (is_simple) {
424       r_parent_uvs[parent_index] = *r_uv;
425     }
426     particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
427   }
428   else {
429     /* Calculate UVs for child particles. */
430     if (!is_simple) {
431       particle_interpolate_children_uvs(psys, psmd, num_uv_layers, child_index, mtfaces, *r_uv);
432     }
433     else if (!r_parent_uvs[psys->child[child_index].parent]) {
434       r_parent_uvs[psys->child[child_index].parent] = *r_uv;
435       particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv);
436     }
437   }
438 }
439 
particle_calculate_mcol(ParticleSystem * psys,ParticleSystemModifierData * psmd,const bool is_simple,const int num_col_layers,const int parent_index,const int child_index,MCol ** mcols,MCol ** r_parent_mcol,MCol ** r_mcol)440 static void particle_calculate_mcol(ParticleSystem *psys,
441                                     ParticleSystemModifierData *psmd,
442                                     const bool is_simple,
443                                     const int num_col_layers,
444                                     const int parent_index,
445                                     const int child_index,
446                                     /*const*/ MCol **mcols,
447                                     MCol **r_parent_mcol,
448                                     MCol **r_mcol)
449 {
450   if (psmd == NULL) {
451     return;
452   }
453   if (is_simple) {
454     if (r_parent_mcol[parent_index] != NULL) {
455       *r_mcol = r_parent_mcol[parent_index];
456     }
457     else {
458       *r_mcol = MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol");
459     }
460   }
461   else {
462     *r_mcol = MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol");
463   }
464   if (child_index == -1) {
465     /* Calculate MCols for parent particles. */
466     if (is_simple) {
467       r_parent_mcol[parent_index] = *r_mcol;
468     }
469     particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
470   }
471   else {
472     /* Calculate MCols for child particles. */
473     if (!is_simple) {
474       particle_interpolate_children_mcol(psys, psmd, num_col_layers, child_index, mcols, *r_mcol);
475     }
476     else if (!r_parent_mcol[psys->child[child_index].parent]) {
477       r_parent_mcol[psys->child[child_index].parent] = *r_mcol;
478       particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol);
479     }
480   }
481 }
482 
483 /* Will return last filled index. */
484 typedef enum ParticleSource {
485   PARTICLE_SOURCE_PARENT,
486   PARTICLE_SOURCE_CHILDREN,
487 } ParticleSource;
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,MTFace ** mtfaces,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)488 static int particle_batch_cache_fill_segments(ParticleSystem *psys,
489                                               ParticleSystemModifierData *psmd,
490                                               ParticleCacheKey **path_cache,
491                                               const ParticleSource particle_source,
492                                               const int global_offset,
493                                               const int start_index,
494                                               const int num_path_keys,
495                                               const int num_uv_layers,
496                                               const int num_col_layers,
497                                               /*const*/ MTFace **mtfaces,
498                                               /*const*/ MCol **mcols,
499                                               uint *uv_id,
500                                               uint *col_id,
501                                               float (***r_parent_uvs)[2],
502                                               MCol ***r_parent_mcol,
503                                               GPUIndexBufBuilder *elb,
504                                               HairAttributeID *attr_id,
505                                               ParticleHairCache *hair_cache)
506 {
507   const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
508   const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
509   if (is_simple && *r_parent_uvs == NULL) {
510     /* TODO(sergey): For edit mode it should be edit->totcached. */
511     *r_parent_uvs = MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs");
512   }
513   if (is_simple && *r_parent_mcol == NULL) {
514     *r_parent_mcol = MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol");
515   }
516   int curr_point = start_index;
517   for (int i = 0; i < num_path_keys; i++) {
518     ParticleCacheKey *path = path_cache[i];
519     if (path->segments <= 0) {
520       continue;
521     }
522     float tangent[3];
523     float(*uv)[2] = NULL;
524     MCol *mcol = NULL;
525     particle_calculate_mcol(psys,
526                             psmd,
527                             is_simple,
528                             num_col_layers,
529                             is_child ? psys->child[i].parent : i,
530                             is_child ? i : -1,
531                             mcols,
532                             *r_parent_mcol,
533                             &mcol);
534     particle_calculate_uvs(psys,
535                            psmd,
536                            is_simple,
537                            num_uv_layers,
538                            is_child ? psys->child[i].parent : i,
539                            is_child ? i : -1,
540                            mtfaces,
541                            *r_parent_uvs,
542                            &uv);
543     for (int j = 0; j < path->segments; j++) {
544       if (j == 0) {
545         sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
546       }
547       else {
548         sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
549       }
550       GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[j].co);
551       GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
552       GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &i);
553       if (psmd != NULL) {
554         for (int k = 0; k < num_uv_layers; k++) {
555           GPU_vertbuf_attr_set(
556               hair_cache->pos,
557               uv_id[k],
558               curr_point,
559               (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] : uv[k]);
560         }
561         for (int k = 0; k < num_col_layers; k++) {
562           /* TODO Put the conversion outside the loop */
563           ushort scol[4];
564           particle_pack_mcol(
565               (is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] : &mcol[k],
566               scol);
567           GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
568         }
569       }
570       GPU_indexbuf_add_generic_vert(elb, curr_point);
571       curr_point++;
572     }
573     sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
574 
575     int global_index = i + global_offset;
576     GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[path->segments].co);
577     GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent);
578     GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &global_index);
579 
580     if (psmd != NULL) {
581       for (int k = 0; k < num_uv_layers; k++) {
582         GPU_vertbuf_attr_set(hair_cache->pos,
583                              uv_id[k],
584                              curr_point,
585                              (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] :
586                                                        uv[k]);
587       }
588       for (int k = 0; k < num_col_layers; k++) {
589         /* TODO Put the conversion outside the loop */
590         ushort scol[4];
591         particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] :
592                                                      &mcol[k],
593                            scol);
594         GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol);
595       }
596       if (!is_simple) {
597         MEM_freeN(uv);
598         MEM_freeN(mcol);
599       }
600     }
601     /* Finish the segment and add restart primitive. */
602     GPU_indexbuf_add_generic_vert(elb, curr_point);
603     GPU_indexbuf_add_primitive_restart(elb);
604     curr_point++;
605   }
606   return curr_point;
607 }
608 
particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey ** path_cache,const int num_path_keys,GPUVertBufRaw * attr_step)609 static void particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey **path_cache,
610                                                         const int num_path_keys,
611                                                         GPUVertBufRaw *attr_step)
612 {
613   for (int i = 0; i < num_path_keys; i++) {
614     ParticleCacheKey *path = path_cache[i];
615     if (path->segments <= 0) {
616       continue;
617     }
618     float total_len = 0.0f;
619     float *co_prev = NULL, *seg_data_first;
620     for (int j = 0; j <= path->segments; j++) {
621       float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
622       copy_v3_v3(seg_data, path[j].co);
623       if (co_prev) {
624         total_len += len_v3v3(co_prev, path[j].co);
625       }
626       else {
627         seg_data_first = seg_data;
628       }
629       seg_data[3] = total_len;
630       co_prev = path[j].co;
631     }
632     if (total_len > 0.0f) {
633       /* Divide by total length to have a [0-1] number. */
634       for (int j = 0; j <= path->segments; j++, seg_data_first += 4) {
635         seg_data_first[3] /= total_len;
636       }
637     }
638   }
639 }
640 
particle_key_weight(const ParticleData * particle,int strand,float t)641 static float particle_key_weight(const ParticleData *particle, int strand, float t)
642 {
643   const ParticleData *part = particle + strand;
644   const HairKey *hkeys = part->hair;
645   float edit_key_seg_t = 1.0f / (part->totkey - 1);
646   if (t == 1.0) {
647     return hkeys[part->totkey - 1].weight;
648   }
649 
650   float interp = t / edit_key_seg_t;
651   int index = (int)interp;
652   interp -= floorf(interp); /* Time between 2 edit key */
653   float s1 = hkeys[index].weight;
654   float s2 = hkeys[index + 1].weight;
655   return s1 + interp * (s2 - s1);
656 }
657 
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)658 static int particle_batch_cache_fill_segments_edit(
659     const PTCacheEdit *UNUSED(edit), /* NULL for weight data */
660     const ParticleData *particle,    /* NULL for select data */
661     ParticleCacheKey **path_cache,
662     const int start_index,
663     const int num_path_keys,
664     GPUIndexBufBuilder *elb,
665     GPUVertBufRaw *attr_step)
666 {
667   int curr_point = start_index;
668   for (int i = 0; i < num_path_keys; i++) {
669     ParticleCacheKey *path = path_cache[i];
670     if (path->segments <= 0) {
671       continue;
672     }
673     for (int j = 0; j <= path->segments; j++) {
674       EditStrandData *seg_data = (EditStrandData *)GPU_vertbuf_raw_step(attr_step);
675       copy_v3_v3(seg_data->pos, path[j].co);
676       float strand_t = (float)(j) / path->segments;
677       if (particle) {
678         float weight = particle_key_weight(particle, i, strand_t);
679         /* NaN or unclamped become 1.0f */
680         seg_data->color = (weight < 1.0f) ? weight : 1.0f;
681       }
682       else {
683         /* Computed in psys_cache_edit_paths_iter(). */
684         seg_data->color = path[j].col[0];
685       }
686       GPU_indexbuf_add_generic_vert(elb, curr_point);
687       curr_point++;
688     }
689     /* Finish the segment and add restart primitive. */
690     GPU_indexbuf_add_primitive_restart(elb);
691   }
692   return curr_point;
693 }
694 
particle_batch_cache_fill_segments_indices(ParticleCacheKey ** path_cache,const int start_index,const int num_path_keys,const int res,GPUIndexBufBuilder * elb)695 static int particle_batch_cache_fill_segments_indices(ParticleCacheKey **path_cache,
696                                                       const int start_index,
697                                                       const int num_path_keys,
698                                                       const int res,
699                                                       GPUIndexBufBuilder *elb)
700 {
701   int curr_point = start_index;
702   for (int i = 0; i < num_path_keys; i++) {
703     ParticleCacheKey *path = path_cache[i];
704     if (path->segments <= 0) {
705       continue;
706     }
707     for (int k = 0; k < res; k++) {
708       GPU_indexbuf_add_generic_vert(elb, curr_point++);
709     }
710     GPU_indexbuf_add_primitive_restart(elb);
711   }
712   return curr_point;
713 }
714 
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,MTFace ** mtfaces,int num_uv_layers,MCol *** r_parent_mcol,GPUVertBufRaw * col_step,MCol ** mcols,int num_col_layers)715 static int particle_batch_cache_fill_strands_data(ParticleSystem *psys,
716                                                   ParticleSystemModifierData *psmd,
717                                                   ParticleCacheKey **path_cache,
718                                                   const ParticleSource particle_source,
719                                                   const int start_index,
720                                                   const int num_path_keys,
721                                                   GPUVertBufRaw *data_step,
722                                                   GPUVertBufRaw *seg_step,
723                                                   float (***r_parent_uvs)[2],
724                                                   GPUVertBufRaw *uv_step,
725                                                   MTFace **mtfaces,
726                                                   int num_uv_layers,
727                                                   MCol ***r_parent_mcol,
728                                                   GPUVertBufRaw *col_step,
729                                                   MCol **mcols,
730                                                   int num_col_layers)
731 {
732   const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES);
733   const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN);
734   if (is_simple && *r_parent_uvs == NULL) {
735     /* TODO(sergey): For edit mode it should be edit->totcached. */
736     *r_parent_uvs = MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs");
737   }
738   if (is_simple && *r_parent_mcol == NULL) {
739     *r_parent_mcol = MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol");
740   }
741   int curr_point = start_index;
742   for (int i = 0; i < num_path_keys; i++) {
743     ParticleCacheKey *path = path_cache[i];
744     if (path->segments <= 0) {
745       continue;
746     }
747 
748     *(uint *)GPU_vertbuf_raw_step(data_step) = curr_point;
749     *(ushort *)GPU_vertbuf_raw_step(seg_step) = path->segments;
750     curr_point += path->segments + 1;
751 
752     if (psmd != NULL) {
753       float(*uv)[2] = NULL;
754       MCol *mcol = NULL;
755 
756       particle_calculate_uvs(psys,
757                              psmd,
758                              is_simple,
759                              num_uv_layers,
760                              is_child ? psys->child[i].parent : i,
761                              is_child ? i : -1,
762                              mtfaces,
763                              *r_parent_uvs,
764                              &uv);
765 
766       particle_calculate_mcol(psys,
767                               psmd,
768                               is_simple,
769                               num_col_layers,
770                               is_child ? psys->child[i].parent : i,
771                               is_child ? i : -1,
772                               mcols,
773                               *r_parent_mcol,
774                               &mcol);
775 
776       for (int k = 0; k < num_uv_layers; k++) {
777         float *t_uv = (float *)GPU_vertbuf_raw_step(uv_step + k);
778         copy_v2_v2(t_uv, uv[k]);
779       }
780       for (int k = 0; k < num_col_layers; k++) {
781         ushort *scol = (ushort *)GPU_vertbuf_raw_step(col_step + k);
782         particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] :
783                                                      &mcol[k],
784                            scol);
785       }
786       if (!is_simple) {
787         MEM_freeN(uv);
788         MEM_freeN(mcol);
789       }
790     }
791   }
792   return curr_point;
793 }
794 
particle_batch_cache_ensure_procedural_final_points(ParticleHairCache * cache,int subdiv)795 static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache,
796                                                                 int subdiv)
797 {
798   /* Same format as point_tex. */
799   GPUVertFormat format = {0};
800   GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
801 
802   cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format(&format);
803 
804   /* Create a destination buffer for the transform feedback. Sized appropriately */
805   /* Those are points! not line segments. */
806   GPU_vertbuf_data_alloc(cache->final[subdiv].proc_buf,
807                          cache->final[subdiv].strands_res * cache->strands_len);
808 
809   /* Create vbo immediately to bind to texture buffer. */
810   GPU_vertbuf_use(cache->final[subdiv].proc_buf);
811 
812   cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf("part_proc",
813                                                                   cache->final[subdiv].proc_buf);
814 }
815 
particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit * edit,ParticleSystem * psys,ModifierData * md,ParticleHairCache * cache)816 static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit,
817                                                                ParticleSystem *psys,
818                                                                ModifierData *md,
819                                                                ParticleHairCache *cache)
820 {
821   int active_uv = 0;
822   int render_uv = 0;
823   int active_col = 0;
824   int render_col = 0;
825 
826   ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
827 
828   if (psmd != NULL && psmd->mesh_final != NULL) {
829     if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) {
830       cache->num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV);
831       active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
832       render_uv = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
833     }
834     if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) {
835       cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL);
836       active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL);
837       render_col = CustomData_get_render_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL);
838     }
839   }
840 
841   GPUVertBufRaw data_step, seg_step;
842   GPUVertBufRaw uv_step[MAX_MTFACE];
843   GPUVertBufRaw col_step[MAX_MCOL];
844 
845   MTFace *mtfaces[MAX_MTFACE] = {NULL};
846   MCol *mcols[MAX_MCOL] = {NULL};
847   float(**parent_uvs)[2] = NULL;
848   MCol **parent_mcol = NULL;
849 
850   GPUVertFormat format_data = {0};
851   uint data_id = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
852 
853   GPUVertFormat format_seg = {0};
854   uint seg_id = GPU_vertformat_attr_add(&format_seg, "data", GPU_COMP_U16, 1, GPU_FETCH_INT);
855 
856   GPUVertFormat format_uv = {0};
857   uint uv_id = GPU_vertformat_attr_add(&format_uv, "uv", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
858 
859   GPUVertFormat format_col = {0};
860   uint col_id = GPU_vertformat_attr_add(
861       &format_col, "col", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
862 
863   memset(cache->uv_layer_names, 0, sizeof(cache->uv_layer_names));
864   memset(cache->col_layer_names, 0, sizeof(cache->col_layer_names));
865 
866   /* Strand Data */
867   cache->proc_strand_buf = GPU_vertbuf_create_with_format(&format_data);
868   GPU_vertbuf_data_alloc(cache->proc_strand_buf, cache->strands_len);
869   GPU_vertbuf_attr_get_raw_data(cache->proc_strand_buf, data_id, &data_step);
870 
871   cache->proc_strand_seg_buf = GPU_vertbuf_create_with_format(&format_seg);
872   GPU_vertbuf_data_alloc(cache->proc_strand_seg_buf, cache->strands_len);
873   GPU_vertbuf_attr_get_raw_data(cache->proc_strand_seg_buf, seg_id, &seg_step);
874 
875   /* UV layers */
876   for (int i = 0; i < cache->num_uv_layers; i++) {
877     cache->proc_uv_buf[i] = GPU_vertbuf_create_with_format(&format_uv);
878     GPU_vertbuf_data_alloc(cache->proc_uv_buf[i], cache->strands_len);
879     GPU_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]);
880 
881     char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
882     const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
883     GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
884 
885     int n = 0;
886     BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "u%s", attr_safe_name);
887     BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%s", attr_safe_name);
888 
889     if (i == active_uv) {
890       BLI_strncpy(cache->uv_layer_names[i][n++], "au", MAX_LAYER_NAME_LEN);
891     }
892     if (i == render_uv) {
893       BLI_strncpy(cache->uv_layer_names[i][n++], "u", MAX_LAYER_NAME_LEN);
894     }
895   }
896   /* Vertex colors */
897   for (int i = 0; i < cache->num_col_layers; i++) {
898     cache->proc_col_buf[i] = GPU_vertbuf_create_with_format(&format_col);
899     GPU_vertbuf_data_alloc(cache->proc_col_buf[i], cache->strands_len);
900     GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]);
901 
902     char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
903     const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i);
904     GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
905 
906     int n = 0;
907     BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "c%s", attr_safe_name);
908 
909     /* We only do vcols auto name that are not overridden by uvs */
910     if (CustomData_get_named_layer_index(&psmd->mesh_final->ldata, CD_MLOOPUV, name) == -1) {
911       BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%s", attr_safe_name);
912     }
913 
914     if (i == active_col) {
915       BLI_strncpy(cache->col_layer_names[i][n++], "ac", MAX_LAYER_NAME_LEN);
916     }
917     if (i == render_col) {
918       BLI_strncpy(cache->col_layer_names[i][n++], "c", MAX_LAYER_NAME_LEN);
919     }
920   }
921 
922   if (cache->num_uv_layers || cache->num_col_layers) {
923     BKE_mesh_tessface_ensure(psmd->mesh_final);
924     if (cache->num_uv_layers) {
925       for (int j = 0; j < cache->num_uv_layers; j++) {
926         mtfaces[j] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, j);
927       }
928     }
929     if (cache->num_col_layers) {
930       for (int j = 0; j < cache->num_col_layers; j++) {
931         mcols[j] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j);
932       }
933     }
934   }
935 
936   if (edit != NULL && edit->pathcache != NULL) {
937     particle_batch_cache_fill_strands_data(psys,
938                                            psmd,
939                                            edit->pathcache,
940                                            PARTICLE_SOURCE_PARENT,
941                                            0,
942                                            edit->totcached,
943                                            &data_step,
944                                            &seg_step,
945                                            &parent_uvs,
946                                            uv_step,
947                                            (MTFace **)mtfaces,
948                                            cache->num_uv_layers,
949                                            &parent_mcol,
950                                            col_step,
951                                            (MCol **)mcols,
952                                            cache->num_col_layers);
953   }
954   else {
955     int curr_point = 0;
956     if ((psys->pathcache != NULL) &&
957         (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
958       curr_point = particle_batch_cache_fill_strands_data(psys,
959                                                           psmd,
960                                                           psys->pathcache,
961                                                           PARTICLE_SOURCE_PARENT,
962                                                           0,
963                                                           psys->totpart,
964                                                           &data_step,
965                                                           &seg_step,
966                                                           &parent_uvs,
967                                                           uv_step,
968                                                           (MTFace **)mtfaces,
969                                                           cache->num_uv_layers,
970                                                           &parent_mcol,
971                                                           col_step,
972                                                           (MCol **)mcols,
973                                                           cache->num_col_layers);
974     }
975     if (psys->childcache) {
976       const int child_count = psys->totchild * psys->part->disp / 100;
977       curr_point = particle_batch_cache_fill_strands_data(psys,
978                                                           psmd,
979                                                           psys->childcache,
980                                                           PARTICLE_SOURCE_CHILDREN,
981                                                           curr_point,
982                                                           child_count,
983                                                           &data_step,
984                                                           &seg_step,
985                                                           &parent_uvs,
986                                                           uv_step,
987                                                           (MTFace **)mtfaces,
988                                                           cache->num_uv_layers,
989                                                           &parent_mcol,
990                                                           col_step,
991                                                           (MCol **)mcols,
992                                                           cache->num_col_layers);
993     }
994   }
995   /* Cleanup. */
996   if (parent_uvs != NULL) {
997     /* TODO(sergey): For edit mode it should be edit->totcached. */
998     for (int i = 0; i < psys->totpart; i++) {
999       MEM_SAFE_FREE(parent_uvs[i]);
1000     }
1001     MEM_freeN(parent_uvs);
1002   }
1003   if (parent_mcol != NULL) {
1004     for (int i = 0; i < psys->totpart; i++) {
1005       MEM_SAFE_FREE(parent_mcol[i]);
1006     }
1007     MEM_freeN(parent_mcol);
1008   }
1009 
1010   /* Create vbo immediately to bind to texture buffer. */
1011   GPU_vertbuf_use(cache->proc_strand_buf);
1012   cache->strand_tex = GPU_texture_create_from_vertbuf("part_strand", cache->proc_strand_buf);
1013 
1014   GPU_vertbuf_use(cache->proc_strand_seg_buf);
1015   cache->strand_seg_tex = GPU_texture_create_from_vertbuf("part_strand_seg",
1016                                                           cache->proc_strand_seg_buf);
1017 
1018   for (int i = 0; i < cache->num_uv_layers; i++) {
1019     GPU_vertbuf_use(cache->proc_uv_buf[i]);
1020     cache->uv_tex[i] = GPU_texture_create_from_vertbuf("part_uv", cache->proc_uv_buf[i]);
1021   }
1022   for (int i = 0; i < cache->num_col_layers; i++) {
1023     GPU_vertbuf_use(cache->proc_col_buf[i]);
1024     cache->col_tex[i] = GPU_texture_create_from_vertbuf("part_col", cache->proc_col_buf[i]);
1025   }
1026 }
1027 
particle_batch_cache_ensure_procedural_indices(PTCacheEdit * edit,ParticleSystem * psys,ParticleHairCache * cache,int thickness_res,int subdiv)1028 static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit,
1029                                                            ParticleSystem *psys,
1030                                                            ParticleHairCache *cache,
1031                                                            int thickness_res,
1032                                                            int subdiv)
1033 {
1034   BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
1035 
1036   if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) {
1037     return;
1038   }
1039 
1040   int verts_per_hair = cache->final[subdiv].strands_res * thickness_res;
1041   /* +1 for primitive restart */
1042   int element_count = (verts_per_hair + 1) * cache->strands_len;
1043   GPUPrimType prim_type = (thickness_res == 1) ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP;
1044 
1045   static GPUVertFormat format = {0};
1046   GPU_vertformat_clear(&format);
1047 
1048   /* initialize vertex format */
1049   GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
1050 
1051   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
1052   GPU_vertbuf_data_alloc(vbo, 1);
1053 
1054   GPUIndexBufBuilder elb;
1055   GPU_indexbuf_init_ex(&elb, prim_type, element_count, element_count);
1056 
1057   if (edit != NULL && edit->pathcache != NULL) {
1058     particle_batch_cache_fill_segments_indices(
1059         edit->pathcache, 0, edit->totcached, verts_per_hair, &elb);
1060   }
1061   else {
1062     int curr_point = 0;
1063     if ((psys->pathcache != NULL) &&
1064         (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
1065       curr_point = particle_batch_cache_fill_segments_indices(
1066           psys->pathcache, 0, psys->totpart, verts_per_hair, &elb);
1067     }
1068     if (psys->childcache) {
1069       const int child_count = psys->totchild * psys->part->disp / 100;
1070       curr_point = particle_batch_cache_fill_segments_indices(
1071           psys->childcache, curr_point, child_count, verts_per_hair, &elb);
1072     }
1073   }
1074 
1075   cache->final[subdiv].proc_hairs[thickness_res - 1] = GPU_batch_create_ex(
1076       prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
1077 }
1078 
particle_batch_cache_ensure_procedural_pos(PTCacheEdit * edit,ParticleSystem * psys,ParticleHairCache * cache)1079 static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit,
1080                                                        ParticleSystem *psys,
1081                                                        ParticleHairCache *cache)
1082 {
1083   if (cache->proc_point_buf != NULL) {
1084     return;
1085   }
1086 
1087   /* initialize vertex format */
1088   GPUVertFormat format = {0};
1089   uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1090 
1091   cache->proc_point_buf = GPU_vertbuf_create_with_format(&format);
1092   GPU_vertbuf_data_alloc(cache->proc_point_buf, cache->point_len);
1093 
1094   GPUVertBufRaw pos_step;
1095   GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step);
1096 
1097   if (edit != NULL && edit->pathcache != NULL) {
1098     particle_batch_cache_fill_segments_proc_pos(edit->pathcache, edit->totcached, &pos_step);
1099   }
1100   else {
1101     if ((psys->pathcache != NULL) &&
1102         (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
1103       particle_batch_cache_fill_segments_proc_pos(psys->pathcache, psys->totpart, &pos_step);
1104     }
1105     if (psys->childcache) {
1106       const int child_count = psys->totchild * psys->part->disp / 100;
1107       particle_batch_cache_fill_segments_proc_pos(psys->childcache, child_count, &pos_step);
1108     }
1109   }
1110 
1111   /* Create vbo immediately to bind to texture buffer. */
1112   GPU_vertbuf_use(cache->proc_point_buf);
1113 
1114   cache->point_tex = GPU_texture_create_from_vertbuf("part_point", cache->proc_point_buf);
1115 }
1116 
particle_batch_cache_ensure_pos_and_seg(PTCacheEdit * edit,ParticleSystem * psys,ModifierData * md,ParticleHairCache * hair_cache)1117 static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
1118                                                     ParticleSystem *psys,
1119                                                     ModifierData *md,
1120                                                     ParticleHairCache *hair_cache)
1121 {
1122   if (hair_cache->pos != NULL && hair_cache->indices != NULL) {
1123     return;
1124   }
1125 
1126   int curr_point = 0;
1127   ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
1128 
1129   GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
1130   GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
1131 
1132   static GPUVertFormat format = {0};
1133   HairAttributeID attr_id;
1134   uint *uv_id = NULL;
1135   uint *col_id = NULL;
1136   int num_uv_layers = 0;
1137   int num_col_layers = 0;
1138   int active_uv = 0;
1139   int active_col = 0;
1140   MTFace **mtfaces = NULL;
1141   MCol **mcols = NULL;
1142   float(**parent_uvs)[2] = NULL;
1143   MCol **parent_mcol = NULL;
1144 
1145   if (psmd != NULL) {
1146     if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) {
1147       num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV);
1148       active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
1149     }
1150     if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) {
1151       num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL);
1152       active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL);
1153     }
1154   }
1155 
1156   GPU_vertformat_clear(&format);
1157 
1158   /* initialize vertex format */
1159   attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1160   attr_id.tan = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1161   attr_id.ind = GPU_vertformat_attr_add(&format, "ind", GPU_COMP_I32, 1, GPU_FETCH_INT);
1162 
1163   if (psmd) {
1164     uv_id = MEM_mallocN(sizeof(*uv_id) * num_uv_layers, "UV attr format");
1165     col_id = MEM_mallocN(sizeof(*col_id) * num_col_layers, "Col attr format");
1166 
1167     for (int i = 0; i < num_uv_layers; i++) {
1168 
1169       char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
1170       const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
1171       GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
1172 
1173       BLI_snprintf(uuid, sizeof(uuid), "u%s", attr_safe_name);
1174       uv_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1175 
1176       if (i == active_uv) {
1177         GPU_vertformat_alias_add(&format, "u");
1178       }
1179     }
1180 
1181     for (int i = 0; i < num_col_layers; i++) {
1182       char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
1183       const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i);
1184       GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
1185 
1186       BLI_snprintf(uuid, sizeof(uuid), "c%s", attr_safe_name);
1187       col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_U16, 4, GPU_FETCH_FLOAT);
1188 
1189       if (i == active_col) {
1190         GPU_vertformat_alias_add(&format, "c");
1191       }
1192     }
1193   }
1194 
1195   hair_cache->pos = GPU_vertbuf_create_with_format(&format);
1196   GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len);
1197 
1198   GPUIndexBufBuilder elb;
1199   GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len);
1200 
1201   if (num_uv_layers || num_col_layers) {
1202     BKE_mesh_tessface_ensure(psmd->mesh_final);
1203     if (num_uv_layers) {
1204       mtfaces = MEM_mallocN(sizeof(*mtfaces) * num_uv_layers, "Faces UV layers");
1205       for (int i = 0; i < num_uv_layers; i++) {
1206         mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, i);
1207       }
1208     }
1209     if (num_col_layers) {
1210       mcols = MEM_mallocN(sizeof(*mcols) * num_col_layers, "Color layers");
1211       for (int i = 0; i < num_col_layers; i++) {
1212         mcols[i] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, i);
1213       }
1214     }
1215   }
1216 
1217   if (edit != NULL && edit->pathcache != NULL) {
1218     curr_point = particle_batch_cache_fill_segments(psys,
1219                                                     psmd,
1220                                                     edit->pathcache,
1221                                                     PARTICLE_SOURCE_PARENT,
1222                                                     0,
1223                                                     0,
1224                                                     edit->totcached,
1225                                                     num_uv_layers,
1226                                                     num_col_layers,
1227                                                     mtfaces,
1228                                                     mcols,
1229                                                     uv_id,
1230                                                     col_id,
1231                                                     &parent_uvs,
1232                                                     &parent_mcol,
1233                                                     &elb,
1234                                                     &attr_id,
1235                                                     hair_cache);
1236   }
1237   else {
1238     if ((psys->pathcache != NULL) &&
1239         (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
1240       curr_point = particle_batch_cache_fill_segments(psys,
1241                                                       psmd,
1242                                                       psys->pathcache,
1243                                                       PARTICLE_SOURCE_PARENT,
1244                                                       0,
1245                                                       0,
1246                                                       psys->totpart,
1247                                                       num_uv_layers,
1248                                                       num_col_layers,
1249                                                       mtfaces,
1250                                                       mcols,
1251                                                       uv_id,
1252                                                       col_id,
1253                                                       &parent_uvs,
1254                                                       &parent_mcol,
1255                                                       &elb,
1256                                                       &attr_id,
1257                                                       hair_cache);
1258     }
1259     if (psys->childcache != NULL) {
1260       const int child_count = psys->totchild * psys->part->disp / 100;
1261       curr_point = particle_batch_cache_fill_segments(psys,
1262                                                       psmd,
1263                                                       psys->childcache,
1264                                                       PARTICLE_SOURCE_CHILDREN,
1265                                                       psys->totpart,
1266                                                       curr_point,
1267                                                       child_count,
1268                                                       num_uv_layers,
1269                                                       num_col_layers,
1270                                                       mtfaces,
1271                                                       mcols,
1272                                                       uv_id,
1273                                                       col_id,
1274                                                       &parent_uvs,
1275                                                       &parent_mcol,
1276                                                       &elb,
1277                                                       &attr_id,
1278                                                       hair_cache);
1279     }
1280   }
1281   /* Cleanup. */
1282   if (parent_uvs != NULL) {
1283     /* TODO(sergey): For edit mode it should be edit->totcached. */
1284     for (int i = 0; i < psys->totpart; i++) {
1285       MEM_SAFE_FREE(parent_uvs[i]);
1286     }
1287     MEM_freeN(parent_uvs);
1288   }
1289   if (parent_mcol != NULL) {
1290     for (int i = 0; i < psys->totpart; i++) {
1291       MEM_SAFE_FREE(parent_mcol[i]);
1292     }
1293     MEM_freeN(parent_mcol);
1294   }
1295   if (num_uv_layers) {
1296     MEM_freeN(mtfaces);
1297   }
1298   if (num_col_layers) {
1299     MEM_freeN(mcols);
1300   }
1301   if (psmd != NULL) {
1302     MEM_freeN(uv_id);
1303   }
1304   hair_cache->indices = GPU_indexbuf_build(&elb);
1305 }
1306 
particle_batch_cache_ensure_pos(Object * object,ParticleSystem * psys,ParticlePointCache * point_cache)1307 static void particle_batch_cache_ensure_pos(Object *object,
1308                                             ParticleSystem *psys,
1309                                             ParticlePointCache *point_cache)
1310 {
1311   if (point_cache->pos != NULL) {
1312     return;
1313   }
1314 
1315   static GPUVertFormat format = {0};
1316   static uint pos_id, rot_id, val_id;
1317   int i, curr_point;
1318   ParticleData *pa;
1319   ParticleKey state;
1320   ParticleSimulationData sim = {NULL};
1321   const DRWContextState *draw_ctx = DRW_context_state_get();
1322 
1323   sim.depsgraph = draw_ctx->depsgraph;
1324   sim.scene = draw_ctx->scene;
1325   sim.ob = object;
1326   sim.psys = psys;
1327   sim.psmd = psys_get_modifier(object, psys);
1328   sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
1329 
1330   GPU_VERTBUF_DISCARD_SAFE(point_cache->pos);
1331 
1332   if (format.attr_len == 0) {
1333     /* initialize vertex format */
1334     pos_id = GPU_vertformat_attr_add(&format, "part_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1335     val_id = GPU_vertformat_attr_add(&format, "part_val", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
1336     rot_id = GPU_vertformat_attr_add(&format, "part_rot", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1337   }
1338 
1339   point_cache->pos = GPU_vertbuf_create_with_format(&format);
1340   GPU_vertbuf_data_alloc(point_cache->pos, psys->totpart);
1341 
1342   for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
1343     state.time = DEG_get_ctime(draw_ctx->depsgraph);
1344     if (!psys_get_particle_state(&sim, i, &state, 0)) {
1345       continue;
1346     }
1347 
1348     float val;
1349 
1350     GPU_vertbuf_attr_set(point_cache->pos, pos_id, curr_point, state.co);
1351     GPU_vertbuf_attr_set(point_cache->pos, rot_id, curr_point, state.rot);
1352 
1353     switch (psys->part->draw_col) {
1354       case PART_DRAW_COL_VEL:
1355         val = len_v3(state.vel) / psys->part->color_vec_max;
1356         break;
1357       case PART_DRAW_COL_ACC:
1358         val = len_v3v3(state.vel, pa->prev_state.vel) /
1359               ((state.time - pa->prev_state.time) * psys->part->color_vec_max);
1360         break;
1361       default:
1362         val = -1.0f;
1363         break;
1364     }
1365 
1366     GPU_vertbuf_attr_set(point_cache->pos, val_id, curr_point, &val);
1367 
1368     curr_point++;
1369   }
1370 
1371   if (curr_point != psys->totpart) {
1372     GPU_vertbuf_data_resize(point_cache->pos, curr_point);
1373   }
1374 }
1375 
drw_particle_update_ptcache_edit(Object * object_eval,ParticleSystem * psys,PTCacheEdit * edit)1376 static void drw_particle_update_ptcache_edit(Object *object_eval,
1377                                              ParticleSystem *psys,
1378                                              PTCacheEdit *edit)
1379 {
1380   if (edit->psys == NULL) {
1381     return;
1382   }
1383   /* NOTE: Get flag from particle system coming from drawing object.
1384    * this is where depsgraph will be setting flags to.
1385    */
1386   const DRWContextState *draw_ctx = DRW_context_state_get();
1387   Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
1388   Object *object_orig = DEG_get_original_object(object_eval);
1389   if (psys->flag & PSYS_HAIR_UPDATED) {
1390     PE_update_object(draw_ctx->depsgraph, scene_orig, object_orig, 0);
1391     psys->flag &= ~PSYS_HAIR_UPDATED;
1392   }
1393   if (edit->pathcache == NULL) {
1394     Depsgraph *depsgraph = draw_ctx->depsgraph;
1395     psys_cache_edit_paths(depsgraph,
1396                           scene_orig,
1397                           object_orig,
1398                           edit,
1399                           DEG_get_ctime(depsgraph),
1400                           DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
1401   }
1402 }
1403 
drw_particle_update_ptcache(Object * object_eval,ParticleSystem * psys)1404 static void drw_particle_update_ptcache(Object *object_eval, ParticleSystem *psys)
1405 {
1406   if ((object_eval->mode & OB_MODE_PARTICLE_EDIT) == 0) {
1407     return;
1408   }
1409   const DRWContextState *draw_ctx = DRW_context_state_get();
1410   Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
1411   Object *object_orig = DEG_get_original_object(object_eval);
1412   PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, object_orig);
1413   if (edit != NULL) {
1414     drw_particle_update_ptcache_edit(object_eval, psys, edit);
1415   }
1416 }
1417 
1418 typedef struct ParticleDrawSource {
1419   Object *object;
1420   ParticleSystem *psys;
1421   ModifierData *md;
1422   PTCacheEdit *edit;
1423 } ParticleDrawSource;
1424 
drw_particle_get_hair_source(Object * object,ParticleSystem * psys,ModifierData * md,PTCacheEdit * edit,ParticleDrawSource * r_draw_source)1425 static void drw_particle_get_hair_source(Object *object,
1426                                          ParticleSystem *psys,
1427                                          ModifierData *md,
1428                                          PTCacheEdit *edit,
1429                                          ParticleDrawSource *r_draw_source)
1430 {
1431   const DRWContextState *draw_ctx = DRW_context_state_get();
1432   r_draw_source->object = object;
1433   r_draw_source->psys = psys;
1434   r_draw_source->md = md;
1435   r_draw_source->edit = edit;
1436   if (psys_in_edit_mode(draw_ctx->depsgraph, psys)) {
1437     r_draw_source->object = DEG_get_original_object(object);
1438     r_draw_source->psys = psys_orig_get(psys);
1439   }
1440 }
1441 
DRW_particles_batch_cache_get_hair(Object * object,ParticleSystem * psys,ModifierData * md)1442 GPUBatch *DRW_particles_batch_cache_get_hair(Object *object,
1443                                              ParticleSystem *psys,
1444                                              ModifierData *md)
1445 {
1446   ParticleBatchCache *cache = particle_batch_cache_get(psys);
1447   if (cache->hair.hairs == NULL) {
1448     drw_particle_update_ptcache(object, psys);
1449     ParticleDrawSource source;
1450     drw_particle_get_hair_source(object, psys, md, NULL, &source);
1451     ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
1452     particle_batch_cache_ensure_pos_and_seg(source.edit, source.psys, source.md, &cache->hair);
1453     cache->hair.hairs = GPU_batch_create(
1454         GPU_PRIM_LINE_STRIP, cache->hair.pos, cache->hair.indices);
1455   }
1456   return cache->hair.hairs;
1457 }
1458 
DRW_particles_batch_cache_get_dots(Object * object,ParticleSystem * psys)1459 GPUBatch *DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *psys)
1460 {
1461   ParticleBatchCache *cache = particle_batch_cache_get(psys);
1462 
1463   if (cache->point.points == NULL) {
1464     particle_batch_cache_ensure_pos(object, psys, &cache->point);
1465     cache->point.points = GPU_batch_create(GPU_PRIM_POINTS, cache->point.pos, NULL);
1466   }
1467 
1468   return cache->point.points;
1469 }
1470 
particle_batch_cache_ensure_edit_pos_and_seg(PTCacheEdit * edit,ParticleSystem * psys,ModifierData * UNUSED (md),ParticleHairCache * hair_cache,bool use_weight)1471 static void particle_batch_cache_ensure_edit_pos_and_seg(PTCacheEdit *edit,
1472                                                          ParticleSystem *psys,
1473                                                          ModifierData *UNUSED(md),
1474                                                          ParticleHairCache *hair_cache,
1475                                                          bool use_weight)
1476 {
1477   if (hair_cache->pos != NULL && hair_cache->indices != NULL) {
1478     return;
1479   }
1480 
1481   ParticleData *particle = (use_weight) ? psys->particles : NULL;
1482 
1483   GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos);
1484   GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices);
1485 
1486   GPUVertBufRaw data_step;
1487   GPUIndexBufBuilder elb;
1488   uint pos_id, color_id;
1489   GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
1490 
1491   hair_cache->pos = GPU_vertbuf_create_with_format(edit_point_format);
1492   GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len);
1493   GPU_vertbuf_attr_get_raw_data(hair_cache->pos, pos_id, &data_step);
1494 
1495   GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len);
1496 
1497   if (edit != NULL && edit->pathcache != NULL) {
1498     particle_batch_cache_fill_segments_edit(
1499         edit, particle, edit->pathcache, 0, edit->totcached, &elb, &data_step);
1500   }
1501   else {
1502     BLI_assert(!"Hairs are not in edit mode!");
1503   }
1504   hair_cache->indices = GPU_indexbuf_build(&elb);
1505 }
1506 
DRW_particles_batch_cache_get_edit_strands(Object * object,ParticleSystem * psys,PTCacheEdit * edit,bool use_weight)1507 GPUBatch *DRW_particles_batch_cache_get_edit_strands(Object *object,
1508                                                      ParticleSystem *psys,
1509                                                      PTCacheEdit *edit,
1510                                                      bool use_weight)
1511 {
1512   ParticleBatchCache *cache = particle_batch_cache_get(psys);
1513   if (cache->edit_is_weight != use_weight) {
1514     GPU_VERTBUF_DISCARD_SAFE(cache->edit_hair.pos);
1515     GPU_BATCH_DISCARD_SAFE(cache->edit_hair.hairs);
1516   }
1517   if (cache->edit_hair.hairs != NULL) {
1518     return cache->edit_hair.hairs;
1519   }
1520   drw_particle_update_ptcache_edit(object, psys, edit);
1521   ensure_seg_pt_count(edit, psys, &cache->edit_hair);
1522   particle_batch_cache_ensure_edit_pos_and_seg(edit, psys, NULL, &cache->edit_hair, use_weight);
1523   cache->edit_hair.hairs = GPU_batch_create(
1524       GPU_PRIM_LINE_STRIP, cache->edit_hair.pos, cache->edit_hair.indices);
1525   cache->edit_is_weight = use_weight;
1526   return cache->edit_hair.hairs;
1527 }
1528 
ensure_edit_inner_points_count(const PTCacheEdit * edit,ParticleBatchCache * cache)1529 static void ensure_edit_inner_points_count(const PTCacheEdit *edit, ParticleBatchCache *cache)
1530 {
1531   if (cache->edit_inner_pos != NULL) {
1532     return;
1533   }
1534   cache->edit_inner_point_len = 0;
1535   for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1536     const PTCacheEditPoint *point = &edit->points[point_index];
1537     if (point->flag & PEP_HIDE) {
1538       continue;
1539     }
1540     BLI_assert(point->totkey >= 1);
1541     cache->edit_inner_point_len += (point->totkey - 1);
1542   }
1543 }
1544 
particle_batch_cache_ensure_edit_inner_pos(PTCacheEdit * edit,ParticleBatchCache * cache)1545 static void particle_batch_cache_ensure_edit_inner_pos(PTCacheEdit *edit,
1546                                                        ParticleBatchCache *cache)
1547 {
1548   if (cache->edit_inner_pos != NULL) {
1549     return;
1550   }
1551 
1552   uint pos_id, color_id;
1553   GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
1554 
1555   cache->edit_inner_pos = GPU_vertbuf_create_with_format(edit_point_format);
1556   GPU_vertbuf_data_alloc(cache->edit_inner_pos, cache->edit_inner_point_len);
1557 
1558   int global_key_index = 0;
1559   for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1560     const PTCacheEditPoint *point = &edit->points[point_index];
1561     if (point->flag & PEP_HIDE) {
1562       continue;
1563     }
1564     for (int key_index = 0; key_index < point->totkey - 1; key_index++) {
1565       PTCacheEditKey *key = &point->keys[key_index];
1566       float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
1567       GPU_vertbuf_attr_set(cache->edit_inner_pos, pos_id, global_key_index, key->world_co);
1568       GPU_vertbuf_attr_set(cache->edit_inner_pos, color_id, global_key_index, &color);
1569       global_key_index++;
1570     }
1571   }
1572 }
1573 
DRW_particles_batch_cache_get_edit_inner_points(Object * object,ParticleSystem * psys,PTCacheEdit * edit)1574 GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(Object *object,
1575                                                           ParticleSystem *psys,
1576                                                           PTCacheEdit *edit)
1577 {
1578   ParticleBatchCache *cache = particle_batch_cache_get(psys);
1579   if (cache->edit_inner_points != NULL) {
1580     return cache->edit_inner_points;
1581   }
1582   drw_particle_update_ptcache_edit(object, psys, edit);
1583   ensure_edit_inner_points_count(edit, cache);
1584   particle_batch_cache_ensure_edit_inner_pos(edit, cache);
1585   cache->edit_inner_points = GPU_batch_create(GPU_PRIM_POINTS, cache->edit_inner_pos, NULL);
1586   return cache->edit_inner_points;
1587 }
1588 
ensure_edit_tip_points_count(const PTCacheEdit * edit,ParticleBatchCache * cache)1589 static void ensure_edit_tip_points_count(const PTCacheEdit *edit, ParticleBatchCache *cache)
1590 {
1591   if (cache->edit_tip_pos != NULL) {
1592     return;
1593   }
1594   cache->edit_tip_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     cache->edit_tip_point_len += 1;
1601   }
1602 }
1603 
particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit * edit,ParticleBatchCache * cache)1604 static void particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit *edit, ParticleBatchCache *cache)
1605 {
1606   if (cache->edit_tip_pos != NULL) {
1607     return;
1608   }
1609 
1610   uint pos_id, color_id;
1611   GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id);
1612 
1613   cache->edit_tip_pos = GPU_vertbuf_create_with_format(edit_point_format);
1614   GPU_vertbuf_data_alloc(cache->edit_tip_pos, cache->edit_tip_point_len);
1615 
1616   int global_point_index = 0;
1617   for (int point_index = 0; point_index < edit->totpoint; point_index++) {
1618     const PTCacheEditPoint *point = &edit->points[point_index];
1619     if (point->flag & PEP_HIDE) {
1620       continue;
1621     }
1622     PTCacheEditKey *key = &point->keys[point->totkey - 1];
1623     float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f;
1624 
1625     GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, global_point_index, key->world_co);
1626     GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, global_point_index, &color);
1627     global_point_index++;
1628   }
1629 }
1630 
DRW_particles_batch_cache_get_edit_tip_points(Object * object,ParticleSystem * psys,PTCacheEdit * edit)1631 GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(Object *object,
1632                                                         ParticleSystem *psys,
1633                                                         PTCacheEdit *edit)
1634 {
1635   ParticleBatchCache *cache = particle_batch_cache_get(psys);
1636   if (cache->edit_tip_points != NULL) {
1637     return cache->edit_tip_points;
1638   }
1639   drw_particle_update_ptcache_edit(object, psys, edit);
1640   ensure_edit_tip_points_count(edit, cache);
1641   particle_batch_cache_ensure_edit_tip_pos(edit, cache);
1642   cache->edit_tip_points = GPU_batch_create(GPU_PRIM_POINTS, cache->edit_tip_pos, NULL);
1643   return cache->edit_tip_points;
1644 }
1645 
1646 /* Ensure all textures and buffers needed for GPU accelerated drawing. */
particles_ensure_procedural_data(Object * object,ParticleSystem * psys,ModifierData * md,ParticleHairCache ** r_hair_cache,int subdiv,int thickness_res)1647 bool particles_ensure_procedural_data(Object *object,
1648                                       ParticleSystem *psys,
1649                                       ModifierData *md,
1650                                       ParticleHairCache **r_hair_cache,
1651                                       int subdiv,
1652                                       int thickness_res)
1653 {
1654   bool need_ft_update = false;
1655 
1656   drw_particle_update_ptcache(object, psys);
1657 
1658   ParticleDrawSource source;
1659   drw_particle_get_hair_source(object, psys, md, NULL, &source);
1660 
1661   ParticleSettings *part = source.psys->part;
1662   ParticleBatchCache *cache = particle_batch_cache_get(source.psys);
1663   *r_hair_cache = &cache->hair;
1664 
1665   (*r_hair_cache)->final[subdiv].strands_res = 1 << (part->draw_step + subdiv);
1666 
1667   /* Refreshed on combing and simulation. */
1668   if ((*r_hair_cache)->proc_point_buf == NULL) {
1669     ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
1670     particle_batch_cache_ensure_procedural_pos(source.edit, source.psys, &cache->hair);
1671     need_ft_update = true;
1672   }
1673 
1674   /* Refreshed if active layer or custom data changes. */
1675   if ((*r_hair_cache)->strand_tex == NULL) {
1676     particle_batch_cache_ensure_procedural_strand_data(
1677         source.edit, source.psys, source.md, &cache->hair);
1678   }
1679 
1680   /* Refreshed only on subdiv count change. */
1681   if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) {
1682     particle_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv);
1683     need_ft_update = true;
1684   }
1685   if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) {
1686     particle_batch_cache_ensure_procedural_indices(
1687         source.edit, source.psys, &cache->hair, thickness_res, subdiv);
1688   }
1689 
1690   return need_ft_update;
1691 }
1692