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