| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2017 by Blender Foundation. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup draw | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \brief Particle API for render engines | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-29 12:30:20 +02:00
										 |  |  | #include "DRW_render.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_utildefines.h"
 | 
					
						
							|  |  |  | #include "BLI_math_vector.h"
 | 
					
						
							| 
									
										
										
										
											2017-11-14 17:00:10 +11:00
										 |  |  | #include "BLI_string.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-22 19:19:55 +02:00
										 |  |  | #include "BLI_ghash.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-15 13:26:40 +02:00
										 |  |  | #include "DNA_mesh_types.h"
 | 
					
						
							|  |  |  | #include "DNA_meshdata_types.h"
 | 
					
						
							| 
									
										
										
										
											2017-06-22 19:19:55 +02:00
										 |  |  | #include "DNA_modifier_types.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | #include "DNA_particle_types.h"
 | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | #include "DNA_customdata_types.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-15 13:26:40 +02:00
										 |  |  | #include "BKE_mesh.h"
 | 
					
						
							| 
									
										
										
										
											2018-05-08 16:16:53 +02:00
										 |  |  | #include "BKE_particle.h"
 | 
					
						
							|  |  |  | #include "BKE_pointcache.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 17:10:42 +02:00
										 |  |  | #include "ED_particle.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | #include "GPU_batch.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 12:07:27 +02:00
										 |  |  | #include "DEG_depsgraph_query.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | #include "draw_cache_impl.h" /* own include */
 | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | #include "draw_hair_private.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void particle_batch_cache_clear(ParticleSystem *psys); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ---------------------------------------------------------------------- */ | 
					
						
							| 
									
										
										
										
											2018-07-18 00:12:21 +02:00
										 |  |  | /* Particle GPUBatch Cache */ | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-15 11:39:14 +02:00
										 |  |  | typedef struct ParticlePointCache { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUVertBuf *pos; | 
					
						
							|  |  |  |   GPUBatch *points; | 
					
						
							|  |  |  |   int elems_len; | 
					
						
							|  |  |  |   int point_len; | 
					
						
							| 
									
										
										
										
											2018-05-15 11:39:14 +02:00
										 |  |  | } ParticlePointCache; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct ParticleBatchCache { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Object mode strands for hair and points for particle,
 | 
					
						
							|  |  |  |    * strands for paths when in edit mode. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   ParticleHairCache hair;   /* Used for hair strands */ | 
					
						
							|  |  |  |   ParticlePointCache point; /* Used for particle points. */ | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Control points when in edit mode. */ | 
					
						
							|  |  |  |   ParticleHairCache edit_hair; | 
					
						
							| 
									
										
										
										
											2018-05-15 11:39:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUVertBuf *edit_pos; | 
					
						
							|  |  |  |   GPUBatch *edit_strands; | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUVertBuf *edit_inner_pos; | 
					
						
							|  |  |  |   GPUBatch *edit_inner_points; | 
					
						
							|  |  |  |   int edit_inner_point_len; | 
					
						
							| 
									
										
										
										
											2018-05-09 14:59:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPUVertBuf *edit_tip_pos; | 
					
						
							|  |  |  |   GPUBatch *edit_tip_points; | 
					
						
							|  |  |  |   int edit_tip_point_len; | 
					
						
							| 
									
										
										
										
											2018-05-09 14:08:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Settings to determine if cache is invalid. */ | 
					
						
							|  |  |  |   bool is_dirty; | 
					
						
							|  |  |  |   bool edit_is_weight; | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } ParticleBatchCache; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 00:12:21 +02:00
										 |  |  | /* GPUBatch cache management. */ | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 15:02:11 +02:00
										 |  |  | typedef struct HairAttributeID { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   uint pos; | 
					
						
							|  |  |  |   uint tan; | 
					
						
							|  |  |  |   uint ind; | 
					
						
							| 
									
										
										
										
											2018-05-08 15:02:11 +02:00
										 |  |  | } HairAttributeID; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | typedef struct EditStrandData { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   float pos[3]; | 
					
						
							| 
									
										
										
										
											2019-04-24 13:18:17 -03:00
										 |  |  |   float color; | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | } EditStrandData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GPUVertFormat *edit_points_vert_format_get(uint *r_pos_id, uint *r_color_id) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   static GPUVertFormat edit_point_format = {0}; | 
					
						
							|  |  |  |   static uint pos_id, color_id; | 
					
						
							|  |  |  |   if (edit_point_format.attr_len == 0) { | 
					
						
							|  |  |  |     /* Keep in sync with EditStrandData */ | 
					
						
							|  |  |  |     pos_id = GPU_vertformat_attr_add(&edit_point_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  |     color_id = GPU_vertformat_attr_add( | 
					
						
							| 
									
										
										
										
											2019-04-24 13:18:17 -03:00
										 |  |  |         &edit_point_format, "color", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   *r_pos_id = pos_id; | 
					
						
							|  |  |  |   *r_color_id = color_id; | 
					
						
							|  |  |  |   return &edit_point_format; | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | static bool particle_batch_cache_valid(ParticleSystem *psys) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = psys->batch_cache; | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (cache == NULL) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (cache->is_dirty == false) { | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void particle_batch_cache_init(ParticleSystem *psys) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = psys->batch_cache; | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!cache) { | 
					
						
							|  |  |  |     cache = psys->batch_cache = MEM_callocN(sizeof(*cache), __func__); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     memset(cache, 0, sizeof(*cache)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   cache->is_dirty = false; | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ParticleBatchCache *particle_batch_cache_get(ParticleSystem *psys) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!particle_batch_cache_valid(psys)) { | 
					
						
							|  |  |  |     particle_batch_cache_clear(psys); | 
					
						
							|  |  |  |     particle_batch_cache_init(psys); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return psys->batch_cache; | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 10:14:29 -03:00
										 |  |  | void DRW_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode) | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = psys->batch_cache; | 
					
						
							|  |  |  |   if (cache == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   switch (mode) { | 
					
						
							|  |  |  |     case BKE_PARTICLE_BATCH_DIRTY_ALL: | 
					
						
							|  |  |  |       cache->is_dirty = true; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       BLI_assert(0); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-15 11:39:14 +02:00
										 |  |  | static void particle_batch_cache_clear_point(ParticlePointCache *point_cache) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPU_BATCH_DISCARD_SAFE(point_cache->points); | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(point_cache->pos); | 
					
						
							| 
									
										
										
										
											2018-05-15 11:39:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* TODO more granular update tagging. */ | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf); | 
					
						
							|  |  |  |   DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf); | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_seg_buf); | 
					
						
							|  |  |  |   DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex); | 
					
						
							|  |  |  |   DRW_TEXTURE_FREE_SAFE(hair_cache->strand_seg_tex); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < MAX_MTFACE; ++i) { | 
					
						
							|  |  |  |     GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]); | 
					
						
							|  |  |  |     DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (int i = 0; i < MAX_MCOL; ++i) { | 
					
						
							|  |  |  |     GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]); | 
					
						
							|  |  |  |     DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (int i = 0; i < MAX_HAIR_SUBDIV; ++i) { | 
					
						
							|  |  |  |     GPU_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf); | 
					
						
							|  |  |  |     DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex); | 
					
						
							|  |  |  |     for (int j = 0; j < MAX_THICKRES; ++j) { | 
					
						
							|  |  |  |       GPU_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* "Normal" legacy hairs */ | 
					
						
							|  |  |  |   GPU_BATCH_DISCARD_SAFE(hair_cache->hairs); | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos); | 
					
						
							|  |  |  |   GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices); | 
					
						
							| 
									
										
										
										
											2018-05-15 11:39:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | static void particle_batch_cache_clear(ParticleSystem *psys) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = psys->batch_cache; | 
					
						
							|  |  |  |   if (!cache) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   particle_batch_cache_clear_point(&cache->point); | 
					
						
							|  |  |  |   particle_batch_cache_clear_hair(&cache->hair); | 
					
						
							| 
									
										
										
										
											2018-05-09 14:08:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   particle_batch_cache_clear_hair(&cache->edit_hair); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   GPU_BATCH_DISCARD_SAFE(cache->edit_inner_points); | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(cache->edit_inner_pos); | 
					
						
							|  |  |  |   GPU_BATCH_DISCARD_SAFE(cache->edit_tip_points); | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(cache->edit_tip_pos); | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void DRW_particle_batch_cache_free(ParticleSystem *psys) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   particle_batch_cache_clear(psys); | 
					
						
							|  |  |  |   MEM_SAFE_FREE(psys->batch_cache); | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void count_cache_segment_keys(ParticleCacheKey **pathcache, | 
					
						
							|  |  |  |                                      const int num_path_cache_keys, | 
					
						
							|  |  |  |                                      ParticleHairCache *hair_cache) | 
					
						
							| 
									
										
										
										
											2018-05-08 16:09:36 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (int i = 0; i < num_path_cache_keys; i++) { | 
					
						
							|  |  |  |     ParticleCacheKey *path = pathcache[i]; | 
					
						
							|  |  |  |     if (path->segments > 0) { | 
					
						
							|  |  |  |       hair_cache->strands_len++; | 
					
						
							|  |  |  |       hair_cache->elems_len += path->segments + 2; | 
					
						
							|  |  |  |       hair_cache->point_len += path->segments + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-08 16:09:36 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void ensure_seg_pt_count(PTCacheEdit *edit, | 
					
						
							|  |  |  |                                 ParticleSystem *psys, | 
					
						
							|  |  |  |                                 ParticleHairCache *hair_cache) | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if ((hair_cache->pos != NULL && hair_cache->indices != NULL) || | 
					
						
							|  |  |  |       (hair_cache->proc_point_buf != NULL)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   hair_cache->strands_len = 0; | 
					
						
							|  |  |  |   hair_cache->elems_len = 0; | 
					
						
							|  |  |  |   hair_cache->point_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (edit != NULL && edit->pathcache != NULL) { | 
					
						
							|  |  |  |     count_cache_segment_keys(edit->pathcache, edit->totcached, hair_cache); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { | 
					
						
							|  |  |  |       count_cache_segment_keys(psys->pathcache, psys->totpart, hair_cache); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (psys->childcache) { | 
					
						
							|  |  |  |       const int child_count = psys->totchild * psys->part->disp / 100; | 
					
						
							|  |  |  |       count_cache_segment_keys(psys->childcache, child_count, hair_cache); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-08 12:47:13 +02:00
										 |  |  | static void particle_pack_mcol(MCol *mcol, ushort r_scol[3]) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Convert to linear ushort and swizzle */ | 
					
						
							|  |  |  |   r_scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); | 
					
						
							|  |  |  |   r_scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); | 
					
						
							|  |  |  |   r_scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 14:06:00 +02:00
										 |  |  | /* Used by parent particles and simple children. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_calculate_parent_uvs(ParticleSystem *psys, | 
					
						
							|  |  |  |                                           ParticleSystemModifierData *psmd, | 
					
						
							|  |  |  |                                           const int num_uv_layers, | 
					
						
							|  |  |  |                                           const int parent_index, | 
					
						
							|  |  |  |                                           /*const*/ MTFace **mtfaces, | 
					
						
							|  |  |  |                                           float (*r_uv)[2]) | 
					
						
							| 
									
										
										
										
											2018-05-08 14:06:00 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (psmd == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const int emit_from = psmd->psys->part->from; | 
					
						
							|  |  |  |   if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ParticleData *particle = &psys->particles[parent_index]; | 
					
						
							|  |  |  |   int num = particle->num_dmcache; | 
					
						
							|  |  |  |   if (num == DMCACHE_NOTFOUND || num == DMCACHE_ISCHILD) { | 
					
						
							|  |  |  |     if (particle->num < psmd->mesh_final->totface) { | 
					
						
							|  |  |  |       num = particle->num; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (num != DMCACHE_NOTFOUND && num != DMCACHE_ISCHILD) { | 
					
						
							|  |  |  |     MFace *mface = &psmd->mesh_final->mface[num]; | 
					
						
							|  |  |  |     for (int j = 0; j < num_uv_layers; j++) { | 
					
						
							|  |  |  |       psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-08 14:06:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_calculate_parent_mcol(ParticleSystem *psys, | 
					
						
							|  |  |  |                                            ParticleSystemModifierData *psmd, | 
					
						
							|  |  |  |                                            const int num_uv_layers, | 
					
						
							|  |  |  |                                            const int parent_index, | 
					
						
							|  |  |  |                                            /*const*/ MCol **mcols, | 
					
						
							|  |  |  |                                            MCol *r_mcol) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (psmd == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const int emit_from = psmd->psys->part->from; | 
					
						
							|  |  |  |   if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ParticleData *particle = &psys->particles[parent_index]; | 
					
						
							|  |  |  |   int num = particle->num_dmcache; | 
					
						
							|  |  |  |   if (num == DMCACHE_NOTFOUND || num == DMCACHE_ISCHILD) { | 
					
						
							|  |  |  |     if (particle->num < psmd->mesh_final->totface) { | 
					
						
							|  |  |  |       num = particle->num; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (num != DMCACHE_NOTFOUND && num != DMCACHE_ISCHILD) { | 
					
						
							|  |  |  |     MFace *mface = &psmd->mesh_final->mface[num]; | 
					
						
							|  |  |  |     for (int j = 0; j < num_uv_layers; j++) { | 
					
						
							|  |  |  |       psys_interpolate_mcol(mcols[j] + num, mface->v4, particle->fuv, &r_mcol[j]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 14:23:55 +02:00
										 |  |  | /* Used by interpolated children. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_interpolate_children_uvs(ParticleSystem *psys, | 
					
						
							|  |  |  |                                               ParticleSystemModifierData *psmd, | 
					
						
							|  |  |  |                                               const int num_uv_layers, | 
					
						
							|  |  |  |                                               const int child_index, | 
					
						
							|  |  |  |                                               /*const*/ MTFace **mtfaces, | 
					
						
							|  |  |  |                                               float (*r_uv)[2]) | 
					
						
							| 
									
										
										
										
											2018-05-08 14:23:55 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (psmd == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const int emit_from = psmd->psys->part->from; | 
					
						
							|  |  |  |   if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ChildParticle *particle = &psys->child[child_index]; | 
					
						
							|  |  |  |   int num = particle->num; | 
					
						
							|  |  |  |   if (num != DMCACHE_NOTFOUND) { | 
					
						
							|  |  |  |     MFace *mface = &psmd->mesh_final->mface[num]; | 
					
						
							|  |  |  |     for (int j = 0; j < num_uv_layers; j++) { | 
					
						
							|  |  |  |       psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, r_uv[j]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_interpolate_children_mcol(ParticleSystem *psys, | 
					
						
							|  |  |  |                                                ParticleSystemModifierData *psmd, | 
					
						
							|  |  |  |                                                const int num_col_layers, | 
					
						
							|  |  |  |                                                const int child_index, | 
					
						
							|  |  |  |                                                /*const*/ MCol **mcols, | 
					
						
							|  |  |  |                                                MCol *r_mcol) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (psmd == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const int emit_from = psmd->psys->part->from; | 
					
						
							|  |  |  |   if (!ELEM(emit_from, PART_FROM_FACE, PART_FROM_VOLUME)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ChildParticle *particle = &psys->child[child_index]; | 
					
						
							|  |  |  |   int num = particle->num; | 
					
						
							|  |  |  |   if (num != DMCACHE_NOTFOUND) { | 
					
						
							|  |  |  |     MFace *mface = &psmd->mesh_final->mface[num]; | 
					
						
							|  |  |  |     for (int j = 0; j < num_col_layers; j++) { | 
					
						
							|  |  |  |       psys_interpolate_mcol(mcols[j] + num, mface->v4, particle->fuv, &r_mcol[j]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-08 14:23:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_calculate_uvs(ParticleSystem *psys, | 
					
						
							|  |  |  |                                    ParticleSystemModifierData *psmd, | 
					
						
							|  |  |  |                                    const bool is_simple, | 
					
						
							|  |  |  |                                    const int num_uv_layers, | 
					
						
							|  |  |  |                                    const int parent_index, | 
					
						
							|  |  |  |                                    const int child_index, | 
					
						
							|  |  |  |                                    /*const*/ MTFace **mtfaces, | 
					
						
							|  |  |  |                                    float (**r_parent_uvs)[2], | 
					
						
							|  |  |  |                                    float (**r_uv)[2]) | 
					
						
							| 
									
										
										
										
											2018-05-08 14:36:11 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (psmd == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (is_simple) { | 
					
						
							|  |  |  |     if (r_parent_uvs[parent_index] != NULL) { | 
					
						
							|  |  |  |       *r_uv = r_parent_uvs[parent_index]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       *r_uv = MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     *r_uv = MEM_callocN(sizeof(**r_uv) * num_uv_layers, "Particle UVs"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (child_index == -1) { | 
					
						
							|  |  |  |     /* Calculate UVs for parent particles. */ | 
					
						
							|  |  |  |     if (is_simple) { | 
					
						
							|  |  |  |       r_parent_uvs[parent_index] = *r_uv; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     /* Calculate UVs for child particles. */ | 
					
						
							|  |  |  |     if (!is_simple) { | 
					
						
							|  |  |  |       particle_interpolate_children_uvs(psys, psmd, num_uv_layers, child_index, mtfaces, *r_uv); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!r_parent_uvs[psys->child[child_index].parent]) { | 
					
						
							|  |  |  |       r_parent_uvs[psys->child[child_index].parent] = *r_uv; | 
					
						
							|  |  |  |       particle_calculate_parent_uvs(psys, psmd, num_uv_layers, parent_index, mtfaces, *r_uv); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-08 14:36:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_calculate_mcol(ParticleSystem *psys, | 
					
						
							|  |  |  |                                     ParticleSystemModifierData *psmd, | 
					
						
							|  |  |  |                                     const bool is_simple, | 
					
						
							|  |  |  |                                     const int num_col_layers, | 
					
						
							|  |  |  |                                     const int parent_index, | 
					
						
							|  |  |  |                                     const int child_index, | 
					
						
							|  |  |  |                                     /*const*/ MCol **mcols, | 
					
						
							|  |  |  |                                     MCol **r_parent_mcol, | 
					
						
							|  |  |  |                                     MCol **r_mcol) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (psmd == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (is_simple) { | 
					
						
							|  |  |  |     if (r_parent_mcol[parent_index] != NULL) { | 
					
						
							|  |  |  |       *r_mcol = r_parent_mcol[parent_index]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       *r_mcol = MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     *r_mcol = MEM_callocN(sizeof(**r_mcol) * num_col_layers, "Particle MCol"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (child_index == -1) { | 
					
						
							|  |  |  |     /* Calculate MCols for parent particles. */ | 
					
						
							|  |  |  |     if (is_simple) { | 
					
						
							|  |  |  |       r_parent_mcol[parent_index] = *r_mcol; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     /* Calculate MCols for child particles. */ | 
					
						
							|  |  |  |     if (!is_simple) { | 
					
						
							|  |  |  |       particle_interpolate_children_mcol(psys, psmd, num_col_layers, child_index, mcols, *r_mcol); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!r_parent_mcol[psys->child[child_index].parent]) { | 
					
						
							|  |  |  |       r_parent_mcol[psys->child[child_index].parent] = *r_mcol; | 
					
						
							|  |  |  |       particle_calculate_parent_mcol(psys, psmd, num_col_layers, parent_index, mcols, *r_mcol); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 15:02:11 +02:00
										 |  |  | /* Will return last filled index. */ | 
					
						
							| 
									
										
										
										
											2018-05-08 15:37:23 +02:00
										 |  |  | typedef enum ParticleSource { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PARTICLE_SOURCE_PARENT, | 
					
						
							|  |  |  |   PARTICLE_SOURCE_CHILDREN, | 
					
						
							| 
									
										
										
										
											2018-05-08 15:37:23 +02:00
										 |  |  | } ParticleSource; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static int particle_batch_cache_fill_segments(ParticleSystem *psys, | 
					
						
							|  |  |  |                                               ParticleSystemModifierData *psmd, | 
					
						
							|  |  |  |                                               ParticleCacheKey **path_cache, | 
					
						
							|  |  |  |                                               const ParticleSource particle_source, | 
					
						
							|  |  |  |                                               const int global_offset, | 
					
						
							|  |  |  |                                               const int start_index, | 
					
						
							|  |  |  |                                               const int num_path_keys, | 
					
						
							|  |  |  |                                               const int num_uv_layers, | 
					
						
							|  |  |  |                                               const int num_col_layers, | 
					
						
							|  |  |  |                                               /*const*/ MTFace **mtfaces, | 
					
						
							|  |  |  |                                               /*const*/ MCol **mcols, | 
					
						
							|  |  |  |                                               uint *uv_id, | 
					
						
							|  |  |  |                                               uint *col_id, | 
					
						
							|  |  |  |                                               float (***r_parent_uvs)[2], | 
					
						
							|  |  |  |                                               MCol ***r_parent_mcol, | 
					
						
							|  |  |  |                                               GPUIndexBufBuilder *elb, | 
					
						
							|  |  |  |                                               HairAttributeID *attr_id, | 
					
						
							|  |  |  |                                               ParticleHairCache *hair_cache) | 
					
						
							| 
									
										
										
										
											2018-05-08 15:02:11 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES); | 
					
						
							|  |  |  |   const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN); | 
					
						
							|  |  |  |   if (is_simple && *r_parent_uvs == NULL) { | 
					
						
							|  |  |  |     /* TODO(sergey): For edit mode it should be edit->totcached. */ | 
					
						
							|  |  |  |     *r_parent_uvs = MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (is_simple && *r_parent_mcol == NULL) { | 
					
						
							|  |  |  |     *r_parent_mcol = MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   int curr_point = start_index; | 
					
						
							|  |  |  |   for (int i = 0; i < num_path_keys; i++) { | 
					
						
							|  |  |  |     ParticleCacheKey *path = path_cache[i]; | 
					
						
							|  |  |  |     if (path->segments <= 0) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     float tangent[3]; | 
					
						
							|  |  |  |     float(*uv)[2] = NULL; | 
					
						
							|  |  |  |     MCol *mcol = NULL; | 
					
						
							|  |  |  |     particle_calculate_mcol(psys, | 
					
						
							|  |  |  |                             psmd, | 
					
						
							|  |  |  |                             is_simple, | 
					
						
							|  |  |  |                             num_col_layers, | 
					
						
							|  |  |  |                             is_child ? psys->child[i].parent : i, | 
					
						
							|  |  |  |                             is_child ? i : -1, | 
					
						
							|  |  |  |                             mcols, | 
					
						
							|  |  |  |                             *r_parent_mcol, | 
					
						
							|  |  |  |                             &mcol); | 
					
						
							|  |  |  |     particle_calculate_uvs(psys, | 
					
						
							|  |  |  |                            psmd, | 
					
						
							|  |  |  |                            is_simple, | 
					
						
							|  |  |  |                            num_uv_layers, | 
					
						
							|  |  |  |                            is_child ? psys->child[i].parent : i, | 
					
						
							|  |  |  |                            is_child ? i : -1, | 
					
						
							|  |  |  |                            mtfaces, | 
					
						
							|  |  |  |                            *r_parent_uvs, | 
					
						
							|  |  |  |                            &uv); | 
					
						
							|  |  |  |     for (int j = 0; j < path->segments; j++) { | 
					
						
							|  |  |  |       if (j == 0) { | 
					
						
							|  |  |  |         sub_v3_v3v3(tangent, path[j + 1].co, path[j].co); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[j].co); | 
					
						
							|  |  |  |       GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent); | 
					
						
							|  |  |  |       GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &i); | 
					
						
							|  |  |  |       if (psmd != NULL) { | 
					
						
							|  |  |  |         for (int k = 0; k < num_uv_layers; k++) { | 
					
						
							|  |  |  |           GPU_vertbuf_attr_set( | 
					
						
							|  |  |  |               hair_cache->pos, | 
					
						
							|  |  |  |               uv_id[k], | 
					
						
							|  |  |  |               curr_point, | 
					
						
							|  |  |  |               (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] : uv[k]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for (int k = 0; k < num_col_layers; k++) { | 
					
						
							|  |  |  |           /* TODO Put the conversion outside the loop */ | 
					
						
							|  |  |  |           ushort scol[4]; | 
					
						
							|  |  |  |           particle_pack_mcol( | 
					
						
							|  |  |  |               (is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] : &mcol[k], | 
					
						
							|  |  |  |               scol); | 
					
						
							|  |  |  |           GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       GPU_indexbuf_add_generic_vert(elb, curr_point); | 
					
						
							|  |  |  |       curr_point++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int global_index = i + global_offset; | 
					
						
							|  |  |  |     GPU_vertbuf_attr_set(hair_cache->pos, attr_id->pos, curr_point, path[path->segments].co); | 
					
						
							|  |  |  |     GPU_vertbuf_attr_set(hair_cache->pos, attr_id->tan, curr_point, tangent); | 
					
						
							|  |  |  |     GPU_vertbuf_attr_set(hair_cache->pos, attr_id->ind, curr_point, &global_index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (psmd != NULL) { | 
					
						
							|  |  |  |       for (int k = 0; k < num_uv_layers; k++) { | 
					
						
							|  |  |  |         GPU_vertbuf_attr_set(hair_cache->pos, | 
					
						
							|  |  |  |                              uv_id[k], | 
					
						
							|  |  |  |                              curr_point, | 
					
						
							|  |  |  |                              (is_simple && is_child) ? (*r_parent_uvs)[psys->child[i].parent][k] : | 
					
						
							|  |  |  |                                                        uv[k]); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       for (int k = 0; k < num_col_layers; k++) { | 
					
						
							|  |  |  |         /* TODO Put the conversion outside the loop */ | 
					
						
							|  |  |  |         ushort scol[4]; | 
					
						
							|  |  |  |         particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] : | 
					
						
							|  |  |  |                                                      &mcol[k], | 
					
						
							|  |  |  |                            scol); | 
					
						
							|  |  |  |         GPU_vertbuf_attr_set(hair_cache->pos, col_id[k], curr_point, scol); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!is_simple) { | 
					
						
							|  |  |  |         MEM_freeN(uv); | 
					
						
							|  |  |  |         MEM_freeN(mcol); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* Finish the segment and add restart primitive. */ | 
					
						
							|  |  |  |     GPU_indexbuf_add_generic_vert(elb, curr_point); | 
					
						
							|  |  |  |     GPU_indexbuf_add_primitive_restart(elb); | 
					
						
							|  |  |  |     curr_point++; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return curr_point; | 
					
						
							| 
									
										
										
										
											2018-05-08 15:02:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey **path_cache, | 
					
						
							|  |  |  |                                                         const int num_path_keys, | 
					
						
							|  |  |  |                                                         GPUVertBufRaw *attr_step) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (int i = 0; i < num_path_keys; i++) { | 
					
						
							|  |  |  |     ParticleCacheKey *path = path_cache[i]; | 
					
						
							|  |  |  |     if (path->segments <= 0) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     float total_len = 0.0f; | 
					
						
							|  |  |  |     float *co_prev = NULL, *seg_data_first; | 
					
						
							|  |  |  |     for (int j = 0; j <= path->segments; j++) { | 
					
						
							|  |  |  |       float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step); | 
					
						
							|  |  |  |       copy_v3_v3(seg_data, path[j].co); | 
					
						
							|  |  |  |       if (co_prev) { | 
					
						
							|  |  |  |         total_len += len_v3v3(co_prev, path[j].co); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         seg_data_first = seg_data; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       seg_data[3] = total_len; | 
					
						
							|  |  |  |       co_prev = path[j].co; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (total_len > 0.0f) { | 
					
						
							|  |  |  |       /* Divide by total length to have a [0-1] number. */ | 
					
						
							|  |  |  |       for (int j = 0; j <= path->segments; j++, seg_data_first += 4) { | 
					
						
							|  |  |  |         seg_data_first[3] /= total_len; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | static float particle_key_select_ratio(const PTCacheEdit *edit, int strand, float t) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const PTCacheEditPoint *point = &edit->points[strand]; | 
					
						
							|  |  |  |   float edit_key_seg_t = 1.0f / (point->totkey - 1); | 
					
						
							|  |  |  |   if (t == 1.0) { | 
					
						
							|  |  |  |     return (point->keys[point->totkey - 1].flag & PEK_SELECT) ? 1.0f : 0.0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     float interp = t / edit_key_seg_t; | 
					
						
							|  |  |  |     int index = (int)interp; | 
					
						
							|  |  |  |     interp -= floorf(interp); /* Time between 2 edit key */ | 
					
						
							|  |  |  |     float s1 = (point->keys[index].flag & PEK_SELECT) ? 1.0f : 0.0; | 
					
						
							|  |  |  |     float s2 = (point->keys[index + 1].flag & PEK_SELECT) ? 1.0f : 0.0; | 
					
						
							|  |  |  |     return s1 + interp * (s2 - s1); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-27 13:49:00 +01:00
										 |  |  | static float particle_key_weight(const ParticleData *particle, int strand, float t) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const ParticleData *part = particle + strand; | 
					
						
							|  |  |  |   const HairKey *hkeys = part->hair; | 
					
						
							|  |  |  |   float edit_key_seg_t = 1.0f / (part->totkey - 1); | 
					
						
							|  |  |  |   if (t == 1.0) { | 
					
						
							|  |  |  |     return hkeys[part->totkey - 1].weight; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     float interp = t / edit_key_seg_t; | 
					
						
							|  |  |  |     int index = (int)interp; | 
					
						
							|  |  |  |     interp -= floorf(interp); /* Time between 2 edit key */ | 
					
						
							|  |  |  |     float s1 = hkeys[index].weight; | 
					
						
							|  |  |  |     float s2 = hkeys[index + 1].weight; | 
					
						
							|  |  |  |     return s1 + interp * (s2 - s1); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-11-27 13:49:00 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | static int particle_batch_cache_fill_segments_edit( | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     const PTCacheEdit *edit,      /* NULL for weight data */ | 
					
						
							|  |  |  |     const ParticleData *particle, /* NULL for select data */ | 
					
						
							|  |  |  |     ParticleCacheKey **path_cache, | 
					
						
							|  |  |  |     const int start_index, | 
					
						
							|  |  |  |     const int num_path_keys, | 
					
						
							|  |  |  |     GPUIndexBufBuilder *elb, | 
					
						
							|  |  |  |     GPUVertBufRaw *attr_step) | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int curr_point = start_index; | 
					
						
							|  |  |  |   for (int i = 0; i < num_path_keys; i++) { | 
					
						
							|  |  |  |     ParticleCacheKey *path = path_cache[i]; | 
					
						
							|  |  |  |     if (path->segments <= 0) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (int j = 0; j <= path->segments; j++) { | 
					
						
							|  |  |  |       EditStrandData *seg_data = (EditStrandData *)GPU_vertbuf_raw_step(attr_step); | 
					
						
							|  |  |  |       copy_v3_v3(seg_data->pos, path[j].co); | 
					
						
							|  |  |  |       float strand_t = (float)(j) / path->segments; | 
					
						
							|  |  |  |       if (particle) { | 
					
						
							|  |  |  |         float weight = particle_key_weight(particle, i, strand_t); | 
					
						
							| 
									
										
										
										
											2019-04-24 13:18:17 -03:00
										 |  |  |         /* NaN or unclamped become 1.0f */ | 
					
						
							|  |  |  |         seg_data->color = (weight < 1.0f) ? weight : 1.0f; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         float selected = particle_key_select_ratio(edit, i, strand_t); | 
					
						
							| 
									
										
										
										
											2019-04-24 13:18:17 -03:00
										 |  |  |         seg_data->color = selected; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       GPU_indexbuf_add_generic_vert(elb, curr_point); | 
					
						
							|  |  |  |       curr_point++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* Finish the segment and add restart primitive. */ | 
					
						
							|  |  |  |     GPU_indexbuf_add_primitive_restart(elb); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return curr_point; | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static int particle_batch_cache_fill_segments_indices(ParticleCacheKey **path_cache, | 
					
						
							|  |  |  |                                                       const int start_index, | 
					
						
							|  |  |  |                                                       const int num_path_keys, | 
					
						
							|  |  |  |                                                       const int res, | 
					
						
							|  |  |  |                                                       GPUIndexBufBuilder *elb) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int curr_point = start_index; | 
					
						
							|  |  |  |   for (int i = 0; i < num_path_keys; i++) { | 
					
						
							|  |  |  |     ParticleCacheKey *path = path_cache[i]; | 
					
						
							|  |  |  |     if (path->segments <= 0) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (int k = 0; k < res; k++) { | 
					
						
							|  |  |  |       GPU_indexbuf_add_generic_vert(elb, curr_point++); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GPU_indexbuf_add_primitive_restart(elb); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return curr_point; | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static int particle_batch_cache_fill_strands_data(ParticleSystem *psys, | 
					
						
							|  |  |  |                                                   ParticleSystemModifierData *psmd, | 
					
						
							|  |  |  |                                                   ParticleCacheKey **path_cache, | 
					
						
							|  |  |  |                                                   const ParticleSource particle_source, | 
					
						
							|  |  |  |                                                   const int start_index, | 
					
						
							|  |  |  |                                                   const int num_path_keys, | 
					
						
							|  |  |  |                                                   GPUVertBufRaw *data_step, | 
					
						
							|  |  |  |                                                   GPUVertBufRaw *seg_step, | 
					
						
							|  |  |  |                                                   float (***r_parent_uvs)[2], | 
					
						
							|  |  |  |                                                   GPUVertBufRaw *uv_step, | 
					
						
							|  |  |  |                                                   MTFace **mtfaces, | 
					
						
							|  |  |  |                                                   int num_uv_layers, | 
					
						
							|  |  |  |                                                   MCol ***r_parent_mcol, | 
					
						
							|  |  |  |                                                   GPUVertBufRaw *col_step, | 
					
						
							|  |  |  |                                                   MCol **mcols, | 
					
						
							|  |  |  |                                                   int num_col_layers) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const bool is_simple = (psys->part->childtype == PART_CHILD_PARTICLES); | 
					
						
							|  |  |  |   const bool is_child = (particle_source == PARTICLE_SOURCE_CHILDREN); | 
					
						
							|  |  |  |   if (is_simple && *r_parent_uvs == NULL) { | 
					
						
							|  |  |  |     /* TODO(sergey): For edit mode it should be edit->totcached. */ | 
					
						
							|  |  |  |     *r_parent_uvs = MEM_callocN(sizeof(*r_parent_uvs) * psys->totpart, "Parent particle UVs"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (is_simple && *r_parent_mcol == NULL) { | 
					
						
							|  |  |  |     *r_parent_mcol = MEM_callocN(sizeof(*r_parent_mcol) * psys->totpart, "Parent particle MCol"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   int curr_point = start_index; | 
					
						
							|  |  |  |   for (int i = 0; i < num_path_keys; i++) { | 
					
						
							|  |  |  |     ParticleCacheKey *path = path_cache[i]; | 
					
						
							|  |  |  |     if (path->segments <= 0) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *(uint *)GPU_vertbuf_raw_step(data_step) = curr_point; | 
					
						
							|  |  |  |     *(ushort *)GPU_vertbuf_raw_step(seg_step) = path->segments; | 
					
						
							|  |  |  |     curr_point += path->segments + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (psmd != NULL) { | 
					
						
							|  |  |  |       float(*uv)[2] = NULL; | 
					
						
							|  |  |  |       MCol *mcol = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       particle_calculate_uvs(psys, | 
					
						
							|  |  |  |                              psmd, | 
					
						
							|  |  |  |                              is_simple, | 
					
						
							|  |  |  |                              num_uv_layers, | 
					
						
							|  |  |  |                              is_child ? psys->child[i].parent : i, | 
					
						
							|  |  |  |                              is_child ? i : -1, | 
					
						
							|  |  |  |                              mtfaces, | 
					
						
							|  |  |  |                              *r_parent_uvs, | 
					
						
							|  |  |  |                              &uv); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       particle_calculate_mcol(psys, | 
					
						
							|  |  |  |                               psmd, | 
					
						
							|  |  |  |                               is_simple, | 
					
						
							|  |  |  |                               num_col_layers, | 
					
						
							|  |  |  |                               is_child ? psys->child[i].parent : i, | 
					
						
							|  |  |  |                               is_child ? i : -1, | 
					
						
							|  |  |  |                               mcols, | 
					
						
							|  |  |  |                               *r_parent_mcol, | 
					
						
							|  |  |  |                               &mcol); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       for (int k = 0; k < num_uv_layers; k++) { | 
					
						
							|  |  |  |         float *t_uv = (float *)GPU_vertbuf_raw_step(uv_step + k); | 
					
						
							|  |  |  |         copy_v2_v2(t_uv, uv[k]); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       for (int k = 0; k < num_col_layers; k++) { | 
					
						
							|  |  |  |         ushort *scol = (ushort *)GPU_vertbuf_raw_step(col_step + k); | 
					
						
							|  |  |  |         particle_pack_mcol((is_simple && is_child) ? &(*r_parent_mcol)[psys->child[i].parent][k] : | 
					
						
							|  |  |  |                                                      &mcol[k], | 
					
						
							|  |  |  |                            scol); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!is_simple) { | 
					
						
							|  |  |  |         MEM_freeN(uv); | 
					
						
							|  |  |  |         MEM_freeN(mcol); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return curr_point; | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_procedural_final_points(ParticleHairCache *cache, | 
					
						
							|  |  |  |                                                                 int subdiv) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Same format as point_tex. */ | 
					
						
							|  |  |  |   GPUVertFormat format = {0}; | 
					
						
							|  |  |  |   GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format(&format); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Create a destination buffer for the transform feedback. Sized appropriately */ | 
					
						
							|  |  |  |   /* Those are points! not line segments. */ | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(cache->final[subdiv].proc_buf, | 
					
						
							|  |  |  |                          cache->final[subdiv].strands_res * cache->strands_len); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Create vbo immediately to bind to texture buffer. */ | 
					
						
							|  |  |  |   GPU_vertbuf_use(cache->final[subdiv].proc_buf); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf(cache->final[subdiv].proc_buf); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit, | 
					
						
							|  |  |  |                                                                ParticleSystem *psys, | 
					
						
							|  |  |  |                                                                ModifierData *md, | 
					
						
							|  |  |  |                                                                ParticleHairCache *cache) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int active_uv = 0; | 
					
						
							|  |  |  |   int active_col = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (psmd != NULL && psmd->mesh_final != NULL) { | 
					
						
							|  |  |  |     if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) { | 
					
						
							|  |  |  |       cache->num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV); | 
					
						
							|  |  |  |       active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) { | 
					
						
							|  |  |  |       cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL); | 
					
						
							|  |  |  |       active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUVertBufRaw data_step, seg_step; | 
					
						
							|  |  |  |   GPUVertBufRaw uv_step[MAX_MTFACE]; | 
					
						
							|  |  |  |   GPUVertBufRaw col_step[MAX_MCOL]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MTFace *mtfaces[MAX_MTFACE] = {NULL}; | 
					
						
							|  |  |  |   MCol *mcols[MAX_MCOL] = {NULL}; | 
					
						
							|  |  |  |   float(**parent_uvs)[2] = NULL; | 
					
						
							|  |  |  |   MCol **parent_mcol = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUVertFormat format_data = {0}; | 
					
						
							|  |  |  |   uint data_id = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U32, 1, GPU_FETCH_INT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUVertFormat format_seg = {0}; | 
					
						
							|  |  |  |   uint seg_id = GPU_vertformat_attr_add(&format_seg, "data", GPU_COMP_U16, 1, GPU_FETCH_INT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUVertFormat format_uv = {0}; | 
					
						
							|  |  |  |   uint uv_id = GPU_vertformat_attr_add(&format_uv, "uv", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUVertFormat format_col = {0}; | 
					
						
							|  |  |  |   uint col_id = GPU_vertformat_attr_add( | 
					
						
							|  |  |  |       &format_col, "col", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   memset(cache->uv_layer_names, 0, sizeof(cache->uv_layer_names)); | 
					
						
							|  |  |  |   memset(cache->col_layer_names, 0, sizeof(cache->col_layer_names)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Strand Data */ | 
					
						
							|  |  |  |   cache->proc_strand_buf = GPU_vertbuf_create_with_format(&format_data); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(cache->proc_strand_buf, cache->strands_len); | 
					
						
							|  |  |  |   GPU_vertbuf_attr_get_raw_data(cache->proc_strand_buf, data_id, &data_step); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cache->proc_strand_seg_buf = GPU_vertbuf_create_with_format(&format_seg); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(cache->proc_strand_seg_buf, cache->strands_len); | 
					
						
							|  |  |  |   GPU_vertbuf_attr_get_raw_data(cache->proc_strand_seg_buf, seg_id, &seg_step); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* UV layers */ | 
					
						
							|  |  |  |   for (int i = 0; i < cache->num_uv_layers; i++) { | 
					
						
							|  |  |  |     cache->proc_uv_buf[i] = GPU_vertbuf_create_with_format(&format_uv); | 
					
						
							|  |  |  |     GPU_vertbuf_data_alloc(cache->proc_uv_buf[i], cache->strands_len); | 
					
						
							|  |  |  |     GPU_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i); | 
					
						
							|  |  |  |     uint hash = BLI_ghashutil_strhash_p(name); | 
					
						
							|  |  |  |     int n = 0; | 
					
						
							|  |  |  |     BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "u%u", hash); | 
					
						
							|  |  |  |     BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (i == active_uv) { | 
					
						
							|  |  |  |       BLI_strncpy(cache->uv_layer_names[i][n], "u", MAX_LAYER_NAME_LEN); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* Vertex colors */ | 
					
						
							|  |  |  |   for (int i = 0; i < cache->num_col_layers; i++) { | 
					
						
							|  |  |  |     cache->proc_col_buf[i] = GPU_vertbuf_create_with_format(&format_col); | 
					
						
							|  |  |  |     GPU_vertbuf_data_alloc(cache->proc_col_buf[i], cache->strands_len); | 
					
						
							|  |  |  |     GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i); | 
					
						
							|  |  |  |     uint hash = BLI_ghashutil_strhash_p(name); | 
					
						
							|  |  |  |     int n = 0; | 
					
						
							|  |  |  |     BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "c%u", hash); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* We only do vcols auto name that are not overridden by uvs */ | 
					
						
							|  |  |  |     if (CustomData_get_named_layer_index(&psmd->mesh_final->ldata, CD_MLOOPUV, name) == -1) { | 
					
						
							|  |  |  |       BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (i == active_col) { | 
					
						
							|  |  |  |       BLI_strncpy(cache->col_layer_names[i][n], "c", MAX_LAYER_NAME_LEN); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (cache->num_uv_layers || cache->num_col_layers) { | 
					
						
							|  |  |  |     BKE_mesh_tessface_ensure(psmd->mesh_final); | 
					
						
							|  |  |  |     if (cache->num_uv_layers) { | 
					
						
							|  |  |  |       for (int j = 0; j < cache->num_uv_layers; j++) { | 
					
						
							|  |  |  |         mtfaces[j] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, j); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (cache->num_col_layers) { | 
					
						
							|  |  |  |       for (int j = 0; j < cache->num_col_layers; j++) { | 
					
						
							|  |  |  |         mcols[j] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (edit != NULL && edit->pathcache != NULL) { | 
					
						
							|  |  |  |     particle_batch_cache_fill_strands_data(psys, | 
					
						
							|  |  |  |                                            psmd, | 
					
						
							|  |  |  |                                            edit->pathcache, | 
					
						
							|  |  |  |                                            PARTICLE_SOURCE_PARENT, | 
					
						
							|  |  |  |                                            0, | 
					
						
							|  |  |  |                                            edit->totcached, | 
					
						
							|  |  |  |                                            &data_step, | 
					
						
							|  |  |  |                                            &seg_step, | 
					
						
							|  |  |  |                                            &parent_uvs, | 
					
						
							|  |  |  |                                            uv_step, | 
					
						
							|  |  |  |                                            (MTFace **)mtfaces, | 
					
						
							|  |  |  |                                            cache->num_uv_layers, | 
					
						
							|  |  |  |                                            &parent_mcol, | 
					
						
							|  |  |  |                                            col_step, | 
					
						
							|  |  |  |                                            (MCol **)mcols, | 
					
						
							|  |  |  |                                            cache->num_col_layers); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     int curr_point = 0; | 
					
						
							|  |  |  |     if ((psys->pathcache != NULL) && | 
					
						
							|  |  |  |         (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { | 
					
						
							|  |  |  |       curr_point = particle_batch_cache_fill_strands_data(psys, | 
					
						
							|  |  |  |                                                           psmd, | 
					
						
							|  |  |  |                                                           psys->pathcache, | 
					
						
							|  |  |  |                                                           PARTICLE_SOURCE_PARENT, | 
					
						
							|  |  |  |                                                           0, | 
					
						
							|  |  |  |                                                           psys->totpart, | 
					
						
							|  |  |  |                                                           &data_step, | 
					
						
							|  |  |  |                                                           &seg_step, | 
					
						
							|  |  |  |                                                           &parent_uvs, | 
					
						
							|  |  |  |                                                           uv_step, | 
					
						
							|  |  |  |                                                           (MTFace **)mtfaces, | 
					
						
							|  |  |  |                                                           cache->num_uv_layers, | 
					
						
							|  |  |  |                                                           &parent_mcol, | 
					
						
							|  |  |  |                                                           col_step, | 
					
						
							|  |  |  |                                                           (MCol **)mcols, | 
					
						
							|  |  |  |                                                           cache->num_col_layers); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (psys->childcache) { | 
					
						
							|  |  |  |       const int child_count = psys->totchild * psys->part->disp / 100; | 
					
						
							|  |  |  |       curr_point = particle_batch_cache_fill_strands_data(psys, | 
					
						
							|  |  |  |                                                           psmd, | 
					
						
							|  |  |  |                                                           psys->childcache, | 
					
						
							|  |  |  |                                                           PARTICLE_SOURCE_CHILDREN, | 
					
						
							|  |  |  |                                                           curr_point, | 
					
						
							|  |  |  |                                                           child_count, | 
					
						
							|  |  |  |                                                           &data_step, | 
					
						
							|  |  |  |                                                           &seg_step, | 
					
						
							|  |  |  |                                                           &parent_uvs, | 
					
						
							|  |  |  |                                                           uv_step, | 
					
						
							|  |  |  |                                                           (MTFace **)mtfaces, | 
					
						
							|  |  |  |                                                           cache->num_uv_layers, | 
					
						
							|  |  |  |                                                           &parent_mcol, | 
					
						
							|  |  |  |                                                           col_step, | 
					
						
							|  |  |  |                                                           (MCol **)mcols, | 
					
						
							|  |  |  |                                                           cache->num_col_layers); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* Cleanup. */ | 
					
						
							|  |  |  |   if (parent_uvs != NULL) { | 
					
						
							|  |  |  |     /* TODO(sergey): For edit mode it should be edit->totcached. */ | 
					
						
							|  |  |  |     for (int i = 0; i < psys->totpart; i++) { | 
					
						
							|  |  |  |       MEM_SAFE_FREE(parent_uvs[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     MEM_freeN(parent_uvs); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (parent_mcol != NULL) { | 
					
						
							|  |  |  |     for (int i = 0; i < psys->totpart; i++) { | 
					
						
							|  |  |  |       MEM_SAFE_FREE(parent_mcol[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     MEM_freeN(parent_mcol); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Create vbo immediately to bind to texture buffer. */ | 
					
						
							|  |  |  |   GPU_vertbuf_use(cache->proc_strand_buf); | 
					
						
							|  |  |  |   cache->strand_tex = GPU_texture_create_from_vertbuf(cache->proc_strand_buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_vertbuf_use(cache->proc_strand_seg_buf); | 
					
						
							|  |  |  |   cache->strand_seg_tex = GPU_texture_create_from_vertbuf(cache->proc_strand_seg_buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < cache->num_uv_layers; i++) { | 
					
						
							|  |  |  |     GPU_vertbuf_use(cache->proc_uv_buf[i]); | 
					
						
							|  |  |  |     cache->uv_tex[i] = GPU_texture_create_from_vertbuf(cache->proc_uv_buf[i]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (int i = 0; i < cache->num_col_layers; i++) { | 
					
						
							|  |  |  |     GPU_vertbuf_use(cache->proc_col_buf[i]); | 
					
						
							|  |  |  |     cache->col_tex[i] = GPU_texture_create_from_vertbuf(cache->proc_col_buf[i]); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit, | 
					
						
							|  |  |  |                                                            ParticleSystem *psys, | 
					
						
							|  |  |  |                                                            ParticleHairCache *cache, | 
					
						
							|  |  |  |                                                            int thickness_res, | 
					
						
							|  |  |  |                                                            int subdiv) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int verts_per_hair = cache->final[subdiv].strands_res * thickness_res; | 
					
						
							|  |  |  |   /* +1 for primitive restart */ | 
					
						
							|  |  |  |   int element_count = (verts_per_hair + 1) * cache->strands_len; | 
					
						
							|  |  |  |   GPUPrimType prim_type = (thickness_res == 1) ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static GPUVertFormat format = {0}; | 
					
						
							|  |  |  |   GPU_vertformat_clear(&format); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* initialize vertex format */ | 
					
						
							|  |  |  |   GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(vbo, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUIndexBufBuilder elb; | 
					
						
							| 
									
										
										
										
											2019-05-29 00:08:10 +02:00
										 |  |  |   GPU_indexbuf_init_ex(&elb, prim_type, element_count, element_count); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (edit != NULL && edit->pathcache != NULL) { | 
					
						
							|  |  |  |     particle_batch_cache_fill_segments_indices( | 
					
						
							|  |  |  |         edit->pathcache, 0, edit->totcached, verts_per_hair, &elb); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     int curr_point = 0; | 
					
						
							|  |  |  |     if ((psys->pathcache != NULL) && | 
					
						
							|  |  |  |         (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { | 
					
						
							|  |  |  |       curr_point = particle_batch_cache_fill_segments_indices( | 
					
						
							|  |  |  |           psys->pathcache, 0, psys->totpart, verts_per_hair, &elb); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (psys->childcache) { | 
					
						
							|  |  |  |       const int child_count = psys->totchild * psys->part->disp / 100; | 
					
						
							|  |  |  |       curr_point = particle_batch_cache_fill_segments_indices( | 
					
						
							|  |  |  |           psys->childcache, curr_point, child_count, verts_per_hair, &elb); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cache->final[subdiv].proc_hairs[thickness_res - 1] = GPU_batch_create_ex( | 
					
						
							|  |  |  |       prim_type, vbo, GPU_indexbuf_build(&elb), GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, | 
					
						
							|  |  |  |                                                        ParticleSystem *psys, | 
					
						
							|  |  |  |                                                        ParticleHairCache *cache) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (cache->proc_point_buf != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* initialize vertex format */ | 
					
						
							|  |  |  |   GPUVertFormat format = {0}; | 
					
						
							|  |  |  |   uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cache->proc_point_buf = GPU_vertbuf_create_with_format(&format); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(cache->proc_point_buf, cache->point_len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUVertBufRaw pos_step; | 
					
						
							|  |  |  |   GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (edit != NULL && edit->pathcache != NULL) { | 
					
						
							|  |  |  |     particle_batch_cache_fill_segments_proc_pos(edit->pathcache, edit->totcached, &pos_step); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     if ((psys->pathcache != NULL) && | 
					
						
							|  |  |  |         (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { | 
					
						
							|  |  |  |       particle_batch_cache_fill_segments_proc_pos(psys->pathcache, psys->totpart, &pos_step); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (psys->childcache) { | 
					
						
							|  |  |  |       const int child_count = psys->totchild * psys->part->disp / 100; | 
					
						
							|  |  |  |       particle_batch_cache_fill_segments_proc_pos(psys->childcache, child_count, &pos_step); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Create vbo immediately to bind to texture buffer. */ | 
					
						
							|  |  |  |   GPU_vertbuf_use(cache->proc_point_buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cache->point_tex = GPU_texture_create_from_vertbuf(cache->proc_point_buf); | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit, | 
					
						
							|  |  |  |                                                     ParticleSystem *psys, | 
					
						
							|  |  |  |                                                     ModifierData *md, | 
					
						
							|  |  |  |                                                     ParticleHairCache *hair_cache) | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (hair_cache->pos != NULL && hair_cache->indices != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int curr_point = 0; | 
					
						
							|  |  |  |   ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos); | 
					
						
							|  |  |  |   GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static GPUVertFormat format = {0}; | 
					
						
							|  |  |  |   HairAttributeID attr_id; | 
					
						
							|  |  |  |   uint *uv_id = NULL; | 
					
						
							|  |  |  |   uint *col_id = NULL; | 
					
						
							|  |  |  |   int num_uv_layers = 0; | 
					
						
							|  |  |  |   int num_col_layers = 0; | 
					
						
							|  |  |  |   int active_uv = 0; | 
					
						
							|  |  |  |   int active_col = 0; | 
					
						
							|  |  |  |   MTFace **mtfaces = NULL; | 
					
						
							|  |  |  |   MCol **mcols = NULL; | 
					
						
							|  |  |  |   float(**parent_uvs)[2] = NULL; | 
					
						
							|  |  |  |   MCol **parent_mcol = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (psmd != NULL) { | 
					
						
							|  |  |  |     if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) { | 
					
						
							|  |  |  |       num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV); | 
					
						
							|  |  |  |       active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) { | 
					
						
							|  |  |  |       num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL); | 
					
						
							|  |  |  |       active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_vertformat_clear(&format); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* initialize vertex format */ | 
					
						
							|  |  |  |   attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  |   attr_id.tan = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  |   attr_id.ind = GPU_vertformat_attr_add(&format, "ind", GPU_COMP_I32, 1, GPU_FETCH_INT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (psmd) { | 
					
						
							|  |  |  |     uv_id = MEM_mallocN(sizeof(*uv_id) * num_uv_layers, "UV attr format"); | 
					
						
							|  |  |  |     col_id = MEM_mallocN(sizeof(*col_id) * num_col_layers, "Col attr format"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < num_uv_layers; i++) { | 
					
						
							|  |  |  |       const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i); | 
					
						
							|  |  |  |       char uuid[32]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       BLI_snprintf(uuid, sizeof(uuid), "u%u", BLI_ghashutil_strhash_p(name)); | 
					
						
							|  |  |  |       uv_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (i == active_uv) { | 
					
						
							|  |  |  |         GPU_vertformat_alias_add(&format, "u"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = 0; i < num_uv_layers; i++) { | 
					
						
							|  |  |  |       const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i); | 
					
						
							|  |  |  |       char uuid[32]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       BLI_snprintf(uuid, sizeof(uuid), "c%u", BLI_ghashutil_strhash_p(name)); | 
					
						
							|  |  |  |       col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (i == active_col) { | 
					
						
							|  |  |  |         GPU_vertformat_alias_add(&format, "c"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   hair_cache->pos = GPU_vertbuf_create_with_format(&format); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUIndexBufBuilder elb; | 
					
						
							| 
									
										
										
										
											2019-05-29 00:08:10 +02:00
										 |  |  |   GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (num_uv_layers || num_col_layers) { | 
					
						
							|  |  |  |     BKE_mesh_tessface_ensure(psmd->mesh_final); | 
					
						
							|  |  |  |     if (num_uv_layers) { | 
					
						
							|  |  |  |       mtfaces = MEM_mallocN(sizeof(*mtfaces) * num_uv_layers, "Faces UV layers"); | 
					
						
							|  |  |  |       for (int i = 0; i < num_uv_layers; i++) { | 
					
						
							|  |  |  |         mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, i); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (num_col_layers) { | 
					
						
							|  |  |  |       mcols = MEM_mallocN(sizeof(*mcols) * num_col_layers, "Color layers"); | 
					
						
							|  |  |  |       for (int i = 0; i < num_col_layers; i++) { | 
					
						
							|  |  |  |         mcols[i] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, i); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (edit != NULL && edit->pathcache != NULL) { | 
					
						
							|  |  |  |     curr_point = particle_batch_cache_fill_segments(psys, | 
					
						
							|  |  |  |                                                     psmd, | 
					
						
							|  |  |  |                                                     edit->pathcache, | 
					
						
							|  |  |  |                                                     PARTICLE_SOURCE_PARENT, | 
					
						
							|  |  |  |                                                     0, | 
					
						
							|  |  |  |                                                     0, | 
					
						
							|  |  |  |                                                     edit->totcached, | 
					
						
							|  |  |  |                                                     num_uv_layers, | 
					
						
							|  |  |  |                                                     num_col_layers, | 
					
						
							|  |  |  |                                                     mtfaces, | 
					
						
							|  |  |  |                                                     mcols, | 
					
						
							|  |  |  |                                                     uv_id, | 
					
						
							|  |  |  |                                                     col_id, | 
					
						
							|  |  |  |                                                     &parent_uvs, | 
					
						
							|  |  |  |                                                     &parent_mcol, | 
					
						
							|  |  |  |                                                     &elb, | 
					
						
							|  |  |  |                                                     &attr_id, | 
					
						
							|  |  |  |                                                     hair_cache); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     if ((psys->pathcache != NULL) && | 
					
						
							|  |  |  |         (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { | 
					
						
							|  |  |  |       curr_point = particle_batch_cache_fill_segments(psys, | 
					
						
							|  |  |  |                                                       psmd, | 
					
						
							|  |  |  |                                                       psys->pathcache, | 
					
						
							|  |  |  |                                                       PARTICLE_SOURCE_PARENT, | 
					
						
							|  |  |  |                                                       0, | 
					
						
							|  |  |  |                                                       0, | 
					
						
							|  |  |  |                                                       psys->totpart, | 
					
						
							|  |  |  |                                                       num_uv_layers, | 
					
						
							|  |  |  |                                                       num_col_layers, | 
					
						
							|  |  |  |                                                       mtfaces, | 
					
						
							|  |  |  |                                                       mcols, | 
					
						
							|  |  |  |                                                       uv_id, | 
					
						
							|  |  |  |                                                       col_id, | 
					
						
							|  |  |  |                                                       &parent_uvs, | 
					
						
							|  |  |  |                                                       &parent_mcol, | 
					
						
							|  |  |  |                                                       &elb, | 
					
						
							|  |  |  |                                                       &attr_id, | 
					
						
							|  |  |  |                                                       hair_cache); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (psys->childcache != NULL) { | 
					
						
							|  |  |  |       const int child_count = psys->totchild * psys->part->disp / 100; | 
					
						
							|  |  |  |       curr_point = particle_batch_cache_fill_segments(psys, | 
					
						
							|  |  |  |                                                       psmd, | 
					
						
							|  |  |  |                                                       psys->childcache, | 
					
						
							|  |  |  |                                                       PARTICLE_SOURCE_CHILDREN, | 
					
						
							|  |  |  |                                                       psys->totpart, | 
					
						
							|  |  |  |                                                       curr_point, | 
					
						
							|  |  |  |                                                       child_count, | 
					
						
							|  |  |  |                                                       num_uv_layers, | 
					
						
							|  |  |  |                                                       num_col_layers, | 
					
						
							|  |  |  |                                                       mtfaces, | 
					
						
							|  |  |  |                                                       mcols, | 
					
						
							|  |  |  |                                                       uv_id, | 
					
						
							|  |  |  |                                                       col_id, | 
					
						
							|  |  |  |                                                       &parent_uvs, | 
					
						
							|  |  |  |                                                       &parent_mcol, | 
					
						
							|  |  |  |                                                       &elb, | 
					
						
							|  |  |  |                                                       &attr_id, | 
					
						
							|  |  |  |                                                       hair_cache); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* Cleanup. */ | 
					
						
							|  |  |  |   if (parent_uvs != NULL) { | 
					
						
							|  |  |  |     /* TODO(sergey): For edit mode it should be edit->totcached. */ | 
					
						
							|  |  |  |     for (int i = 0; i < psys->totpart; i++) { | 
					
						
							|  |  |  |       MEM_SAFE_FREE(parent_uvs[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     MEM_freeN(parent_uvs); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (parent_mcol != NULL) { | 
					
						
							|  |  |  |     for (int i = 0; i < psys->totpart; i++) { | 
					
						
							|  |  |  |       MEM_SAFE_FREE(parent_mcol[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     MEM_freeN(parent_mcol); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (num_uv_layers) { | 
					
						
							|  |  |  |     MEM_freeN(mtfaces); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (num_col_layers) { | 
					
						
							|  |  |  |     MEM_freeN(mcols); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (psmd != NULL) { | 
					
						
							|  |  |  |     MEM_freeN(uv_id); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   hair_cache->indices = GPU_indexbuf_build(&elb); | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_pos(Object *object, | 
					
						
							|  |  |  |                                             ParticleSystem *psys, | 
					
						
							|  |  |  |                                             ParticlePointCache *point_cache) | 
					
						
							| 
									
										
										
										
											2017-05-19 17:13:48 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (point_cache->pos != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static GPUVertFormat format = {0}; | 
					
						
							|  |  |  |   static uint pos_id, rot_id, val_id; | 
					
						
							|  |  |  |   int i, curr_point; | 
					
						
							|  |  |  |   ParticleData *pa; | 
					
						
							|  |  |  |   ParticleKey state; | 
					
						
							|  |  |  |   ParticleSimulationData sim = {NULL}; | 
					
						
							|  |  |  |   const DRWContextState *draw_ctx = DRW_context_state_get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   sim.depsgraph = draw_ctx->depsgraph; | 
					
						
							|  |  |  |   sim.scene = draw_ctx->scene; | 
					
						
							|  |  |  |   sim.ob = object; | 
					
						
							|  |  |  |   sim.psys = psys; | 
					
						
							|  |  |  |   sim.psmd = psys_get_modifier(object, psys); | 
					
						
							|  |  |  |   sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (psys->part->phystype == PART_PHYS_KEYED) { | 
					
						
							|  |  |  |     if (psys->flag & PSYS_KEYED) { | 
					
						
							|  |  |  |       psys_count_keyed_targets(&sim); | 
					
						
							|  |  |  |       if (psys->totkeyed == 0) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(point_cache->pos); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (format.attr_len == 0) { | 
					
						
							|  |  |  |     /* initialize vertex format */ | 
					
						
							|  |  |  |     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  |     rot_id = GPU_vertformat_attr_add(&format, "rot", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  |     val_id = GPU_vertformat_attr_add(&format, "val", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   point_cache->pos = GPU_vertbuf_create_with_format(&format); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(point_cache->pos, psys->totpart); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) { | 
					
						
							|  |  |  |     state.time = DEG_get_ctime(draw_ctx->depsgraph); | 
					
						
							|  |  |  |     if (!psys_get_particle_state(&sim, i, &state, 0)) { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     float val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GPU_vertbuf_attr_set(point_cache->pos, pos_id, curr_point, state.co); | 
					
						
							|  |  |  |     GPU_vertbuf_attr_set(point_cache->pos, rot_id, curr_point, state.rot); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (psys->part->draw_col) { | 
					
						
							|  |  |  |       case PART_DRAW_COL_VEL: | 
					
						
							|  |  |  |         val = len_v3(state.vel) / psys->part->color_vec_max; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case PART_DRAW_COL_ACC: | 
					
						
							|  |  |  |         val = len_v3v3(state.vel, pa->prev_state.vel) / | 
					
						
							|  |  |  |               ((state.time - pa->prev_state.time) * psys->part->color_vec_max); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         val = -1.0f; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GPU_vertbuf_attr_set(point_cache->pos, val_id, curr_point, &val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     curr_point++; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (curr_point != psys->totpart) { | 
					
						
							|  |  |  |     GPU_vertbuf_data_resize(point_cache->pos, curr_point); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-19 17:13:48 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void drw_particle_update_ptcache_edit(Object *object_eval, | 
					
						
							|  |  |  |                                              ParticleSystem *psys, | 
					
						
							|  |  |  |                                              PTCacheEdit *edit) | 
					
						
							| 
									
										
										
										
											2018-05-15 12:44:55 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (edit->psys == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* NOTE: Get flag from particle system coming from drawing object.
 | 
					
						
							|  |  |  |    * this is where depsgraph will be setting flags to. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   const DRWContextState *draw_ctx = DRW_context_state_get(); | 
					
						
							|  |  |  |   Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id); | 
					
						
							|  |  |  |   Object *object_orig = DEG_get_original_object(object_eval); | 
					
						
							|  |  |  |   if (psys->flag & PSYS_HAIR_UPDATED) { | 
					
						
							|  |  |  |     PE_update_object(draw_ctx->depsgraph, scene_orig, object_orig, 0); | 
					
						
							|  |  |  |     psys->flag &= ~PSYS_HAIR_UPDATED; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (edit->pathcache == NULL) { | 
					
						
							|  |  |  |     Depsgraph *depsgraph = draw_ctx->depsgraph; | 
					
						
							|  |  |  |     psys_cache_edit_paths(depsgraph, | 
					
						
							|  |  |  |                           scene_orig, | 
					
						
							|  |  |  |                           object_orig, | 
					
						
							|  |  |  |                           edit, | 
					
						
							|  |  |  |                           DEG_get_ctime(depsgraph), | 
					
						
							|  |  |  |                           DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-15 12:44:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void drw_particle_update_ptcache(Object *object_eval, ParticleSystem *psys) | 
					
						
							| 
									
										
										
										
											2018-05-15 12:44:55 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if ((object_eval->mode & OB_MODE_PARTICLE_EDIT) == 0) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const DRWContextState *draw_ctx = DRW_context_state_get(); | 
					
						
							|  |  |  |   Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id); | 
					
						
							|  |  |  |   Object *object_orig = DEG_get_original_object(object_eval); | 
					
						
							|  |  |  |   PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, object_orig); | 
					
						
							|  |  |  |   if (edit != NULL) { | 
					
						
							|  |  |  |     drw_particle_update_ptcache_edit(object_eval, psys, edit); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-15 12:44:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-15 17:22:31 +02:00
										 |  |  | typedef struct ParticleDrawSource { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   Object *object; | 
					
						
							|  |  |  |   ParticleSystem *psys; | 
					
						
							|  |  |  |   ModifierData *md; | 
					
						
							|  |  |  |   PTCacheEdit *edit; | 
					
						
							| 
									
										
										
										
											2018-06-15 17:22:31 +02:00
										 |  |  | } ParticleDrawSource; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void drw_particle_get_hair_source(Object *object, | 
					
						
							|  |  |  |                                          ParticleSystem *psys, | 
					
						
							|  |  |  |                                          ModifierData *md, | 
					
						
							|  |  |  |                                          PTCacheEdit *edit, | 
					
						
							|  |  |  |                                          ParticleDrawSource *r_draw_source) | 
					
						
							| 
									
										
										
										
											2018-06-15 17:22:31 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   r_draw_source->object = object; | 
					
						
							|  |  |  |   r_draw_source->psys = psys; | 
					
						
							|  |  |  |   r_draw_source->md = md; | 
					
						
							|  |  |  |   r_draw_source->edit = edit; | 
					
						
							|  |  |  |   if ((object->mode & OB_MODE_PARTICLE_EDIT) != 0) { | 
					
						
							|  |  |  |     r_draw_source->object = DEG_get_original_object(object); | 
					
						
							|  |  |  |     r_draw_source->psys = psys_orig_get(psys); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-15 17:22:31 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | GPUBatch *DRW_particles_batch_cache_get_hair(Object *object, | 
					
						
							|  |  |  |                                              ParticleSystem *psys, | 
					
						
							|  |  |  |                                              ModifierData *md) | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = particle_batch_cache_get(psys); | 
					
						
							|  |  |  |   if (cache->hair.hairs == NULL) { | 
					
						
							|  |  |  |     drw_particle_update_ptcache(object, psys); | 
					
						
							|  |  |  |     ParticleDrawSource source; | 
					
						
							|  |  |  |     drw_particle_get_hair_source(object, psys, md, NULL, &source); | 
					
						
							|  |  |  |     ensure_seg_pt_count(source.edit, source.psys, &cache->hair); | 
					
						
							|  |  |  |     particle_batch_cache_ensure_pos_and_seg(source.edit, source.psys, source.md, &cache->hair); | 
					
						
							|  |  |  |     cache->hair.hairs = GPU_batch_create( | 
					
						
							|  |  |  |         GPU_PRIM_LINE_STRIP, cache->hair.pos, cache->hair.indices); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return cache->hair.hairs; | 
					
						
							| 
									
										
										
										
											2017-05-09 16:23:47 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-05-19 17:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-18 00:12:21 +02:00
										 |  |  | GPUBatch *DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *psys) | 
					
						
							| 
									
										
										
										
											2017-05-19 17:13:48 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = particle_batch_cache_get(psys); | 
					
						
							| 
									
										
										
										
											2017-05-19 17:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (cache->point.points == NULL) { | 
					
						
							|  |  |  |     particle_batch_cache_ensure_pos(object, psys, &cache->point); | 
					
						
							|  |  |  |     cache->point.points = GPU_batch_create(GPU_PRIM_POINTS, cache->point.pos, NULL); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-19 17:13:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return cache->point.points; | 
					
						
							| 
									
										
										
										
											2017-05-19 17:13:48 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-05-09 11:14:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_edit_pos_and_seg(PTCacheEdit *edit, | 
					
						
							|  |  |  |                                                          ParticleSystem *psys, | 
					
						
							|  |  |  |                                                          ModifierData *UNUSED(md), | 
					
						
							|  |  |  |                                                          ParticleHairCache *hair_cache, | 
					
						
							|  |  |  |                                                          bool use_weight) | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (hair_cache->pos != NULL && hair_cache->indices != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ParticleData *particle = (use_weight) ? psys->particles : NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_VERTBUF_DISCARD_SAFE(hair_cache->pos); | 
					
						
							|  |  |  |   GPU_INDEXBUF_DISCARD_SAFE(hair_cache->indices); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUVertBufRaw data_step; | 
					
						
							|  |  |  |   GPUIndexBufBuilder elb; | 
					
						
							|  |  |  |   uint pos_id, color_id; | 
					
						
							|  |  |  |   GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   hair_cache->pos = GPU_vertbuf_create_with_format(edit_point_format); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(hair_cache->pos, hair_cache->point_len); | 
					
						
							|  |  |  |   GPU_vertbuf_attr_get_raw_data(hair_cache->pos, pos_id, &data_step); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-29 00:08:10 +02:00
										 |  |  |   GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, hair_cache->elems_len, hair_cache->point_len); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (edit != NULL && edit->pathcache != NULL) { | 
					
						
							|  |  |  |     particle_batch_cache_fill_segments_edit( | 
					
						
							|  |  |  |         edit, particle, edit->pathcache, 0, edit->totcached, &elb, &data_step); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     BLI_assert(!"Hairs are not in edit mode!"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   hair_cache->indices = GPU_indexbuf_build(&elb); | 
					
						
							| 
									
										
										
										
											2018-11-26 20:34:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | GPUBatch *DRW_particles_batch_cache_get_edit_strands(Object *object, | 
					
						
							|  |  |  |                                                      ParticleSystem *psys, | 
					
						
							|  |  |  |                                                      PTCacheEdit *edit, | 
					
						
							|  |  |  |                                                      bool use_weight) | 
					
						
							| 
									
										
										
										
											2018-05-09 11:14:27 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = particle_batch_cache_get(psys); | 
					
						
							|  |  |  |   if (cache->edit_is_weight != use_weight) { | 
					
						
							|  |  |  |     GPU_VERTBUF_DISCARD_SAFE(cache->edit_hair.pos); | 
					
						
							|  |  |  |     GPU_BATCH_DISCARD_SAFE(cache->edit_hair.hairs); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (cache->edit_hair.hairs != NULL) { | 
					
						
							|  |  |  |     return cache->edit_hair.hairs; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   drw_particle_update_ptcache_edit(object, psys, edit); | 
					
						
							|  |  |  |   ensure_seg_pt_count(edit, psys, &cache->edit_hair); | 
					
						
							|  |  |  |   particle_batch_cache_ensure_edit_pos_and_seg(edit, psys, NULL, &cache->edit_hair, use_weight); | 
					
						
							|  |  |  |   cache->edit_hair.hairs = GPU_batch_create( | 
					
						
							|  |  |  |       GPU_PRIM_LINE_STRIP, cache->edit_hair.pos, cache->edit_hair.indices); | 
					
						
							|  |  |  |   cache->edit_is_weight = use_weight; | 
					
						
							|  |  |  |   return cache->edit_hair.hairs; | 
					
						
							| 
									
										
										
										
											2018-05-09 11:14:27 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-05-09 14:08:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void ensure_edit_inner_points_count(const PTCacheEdit *edit, ParticleBatchCache *cache) | 
					
						
							| 
									
										
										
										
											2018-05-09 14:08:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (cache->edit_inner_pos != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   cache->edit_inner_point_len = 0; | 
					
						
							|  |  |  |   for (int point_index = 0; point_index < edit->totpoint; point_index++) { | 
					
						
							|  |  |  |     const PTCacheEditPoint *point = &edit->points[point_index]; | 
					
						
							|  |  |  |     BLI_assert(point->totkey >= 1); | 
					
						
							|  |  |  |     cache->edit_inner_point_len += (point->totkey - 1); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-09 14:08:44 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_edit_inner_pos(PTCacheEdit *edit, | 
					
						
							|  |  |  |                                                        ParticleBatchCache *cache) | 
					
						
							| 
									
										
										
										
											2018-05-09 14:59:29 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (cache->edit_inner_pos != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint pos_id, color_id; | 
					
						
							|  |  |  |   GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cache->edit_inner_pos = GPU_vertbuf_create_with_format(edit_point_format); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(cache->edit_inner_pos, cache->edit_inner_point_len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int global_key_index = 0; | 
					
						
							|  |  |  |   for (int point_index = 0; point_index < edit->totpoint; point_index++) { | 
					
						
							|  |  |  |     const PTCacheEditPoint *point = &edit->points[point_index]; | 
					
						
							|  |  |  |     for (int key_index = 0; key_index < point->totkey - 1; key_index++) { | 
					
						
							|  |  |  |       PTCacheEditKey *key = &point->keys[key_index]; | 
					
						
							| 
									
										
										
										
											2019-04-24 13:18:17 -03:00
										 |  |  |       float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       GPU_vertbuf_attr_set(cache->edit_inner_pos, pos_id, global_key_index, key->world_co); | 
					
						
							|  |  |  |       GPU_vertbuf_attr_set(cache->edit_inner_pos, color_id, global_key_index, &color); | 
					
						
							|  |  |  |       global_key_index++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-09 14:08:44 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | GPUBatch *DRW_particles_batch_cache_get_edit_inner_points(Object *object, | 
					
						
							|  |  |  |                                                           ParticleSystem *psys, | 
					
						
							|  |  |  |                                                           PTCacheEdit *edit) | 
					
						
							| 
									
										
										
										
											2018-05-09 14:59:29 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = particle_batch_cache_get(psys); | 
					
						
							|  |  |  |   if (cache->edit_inner_points != NULL) { | 
					
						
							|  |  |  |     return cache->edit_inner_points; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   drw_particle_update_ptcache_edit(object, psys, edit); | 
					
						
							|  |  |  |   ensure_edit_inner_points_count(edit, cache); | 
					
						
							|  |  |  |   particle_batch_cache_ensure_edit_inner_pos(edit, cache); | 
					
						
							|  |  |  |   cache->edit_inner_points = GPU_batch_create(GPU_PRIM_POINTS, cache->edit_inner_pos, NULL); | 
					
						
							|  |  |  |   return cache->edit_inner_points; | 
					
						
							| 
									
										
										
										
											2018-05-09 14:59:29 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void ensure_edit_tip_points_count(const PTCacheEdit *edit, ParticleBatchCache *cache) | 
					
						
							| 
									
										
										
										
											2018-05-09 14:59:29 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (cache->edit_tip_pos != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   cache->edit_tip_point_len = edit->totpoint; | 
					
						
							| 
									
										
										
										
											2018-05-09 14:59:29 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void particle_batch_cache_ensure_edit_tip_pos(PTCacheEdit *edit, ParticleBatchCache *cache) | 
					
						
							| 
									
										
										
										
											2018-05-09 14:59:29 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (cache->edit_tip_pos != NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint pos_id, color_id; | 
					
						
							|  |  |  |   GPUVertFormat *edit_point_format = edit_points_vert_format_get(&pos_id, &color_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cache->edit_tip_pos = GPU_vertbuf_create_with_format(edit_point_format); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(cache->edit_tip_pos, cache->edit_tip_point_len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int point_index = 0; point_index < edit->totpoint; point_index++) { | 
					
						
							|  |  |  |     const PTCacheEditPoint *point = &edit->points[point_index]; | 
					
						
							|  |  |  |     PTCacheEditKey *key = &point->keys[point->totkey - 1]; | 
					
						
							| 
									
										
										
										
											2019-04-24 13:31:35 -03:00
										 |  |  |     float color = (key->flag & PEK_SELECT) ? 1.0f : 0.0f; | 
					
						
							| 
									
										
										
										
											2019-04-24 13:18:17 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     GPU_vertbuf_attr_set(cache->edit_tip_pos, pos_id, point_index, key->world_co); | 
					
						
							|  |  |  |     GPU_vertbuf_attr_set(cache->edit_tip_pos, color_id, point_index, &color); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-05-09 14:59:29 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(Object *object, | 
					
						
							|  |  |  |                                                         ParticleSystem *psys, | 
					
						
							|  |  |  |                                                         PTCacheEdit *edit) | 
					
						
							| 
									
										
										
										
											2018-05-09 14:08:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ParticleBatchCache *cache = particle_batch_cache_get(psys); | 
					
						
							|  |  |  |   if (cache->edit_tip_points != NULL) { | 
					
						
							|  |  |  |     return cache->edit_tip_points; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   drw_particle_update_ptcache_edit(object, psys, edit); | 
					
						
							|  |  |  |   ensure_edit_tip_points_count(edit, cache); | 
					
						
							|  |  |  |   particle_batch_cache_ensure_edit_tip_pos(edit, cache); | 
					
						
							|  |  |  |   cache->edit_tip_points = GPU_batch_create(GPU_PRIM_POINTS, cache->edit_tip_pos, NULL); | 
					
						
							|  |  |  |   return cache->edit_tip_points; | 
					
						
							| 
									
										
										
										
											2018-05-09 14:08:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Ensure all textures and buffers needed for GPU accelerated drawing. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | bool particles_ensure_procedural_data(Object *object, | 
					
						
							|  |  |  |                                       ParticleSystem *psys, | 
					
						
							|  |  |  |                                       ModifierData *md, | 
					
						
							|  |  |  |                                       ParticleHairCache **r_hair_cache, | 
					
						
							|  |  |  |                                       int subdiv, | 
					
						
							|  |  |  |                                       int thickness_res) | 
					
						
							| 
									
										
										
										
											2018-05-29 12:11:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bool need_ft_update = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   drw_particle_update_ptcache(object, psys); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ParticleDrawSource source; | 
					
						
							|  |  |  |   drw_particle_get_hair_source(object, psys, md, NULL, &source); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ParticleSettings *part = source.psys->part; | 
					
						
							|  |  |  |   ParticleBatchCache *cache = particle_batch_cache_get(source.psys); | 
					
						
							|  |  |  |   *r_hair_cache = &cache->hair; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   (*r_hair_cache)->final[subdiv].strands_res = 1 << (part->draw_step + subdiv); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Refreshed on combing and simulation. */ | 
					
						
							|  |  |  |   if ((*r_hair_cache)->proc_point_buf == NULL) { | 
					
						
							|  |  |  |     ensure_seg_pt_count(source.edit, source.psys, &cache->hair); | 
					
						
							|  |  |  |     particle_batch_cache_ensure_procedural_pos(source.edit, source.psys, &cache->hair); | 
					
						
							|  |  |  |     need_ft_update = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Refreshed if active layer or custom data changes. */ | 
					
						
							|  |  |  |   if ((*r_hair_cache)->strand_tex == NULL) { | 
					
						
							|  |  |  |     particle_batch_cache_ensure_procedural_strand_data( | 
					
						
							|  |  |  |         source.edit, source.psys, source.md, &cache->hair); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Refreshed only on subdiv count change. */ | 
					
						
							|  |  |  |   if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) { | 
					
						
							|  |  |  |     particle_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv); | 
					
						
							|  |  |  |     need_ft_update = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) { | 
					
						
							|  |  |  |     particle_batch_cache_ensure_procedural_indices( | 
					
						
							|  |  |  |         source.edit, source.psys, &cache->hair, thickness_res, subdiv); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return need_ft_update; | 
					
						
							| 
									
										
										
										
											2018-05-30 15:26:37 +02:00
										 |  |  | } |