diff options
Diffstat (limited to 'source/blender/draw/modes/particle_mode.c')
-rw-r--r-- | source/blender/draw/modes/particle_mode.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c new file mode 100644 index 00000000000..19c3ddd4b50 --- /dev/null +++ b/source/blender/draw/modes/particle_mode.c @@ -0,0 +1,246 @@ +/* + * Copyright 2016, Blender Foundation. + * + * 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. + * + * Contributor(s): Blender Institute + * + */ + +/** \file blender/draw/modes/particle_mode.c + * \ingroup draw + */ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" + +#include "BKE_particle.h" +#include "BKE_pointcache.h" + +#include "GPU_shader.h" +#include "GPU_batch.h" + +#include "draw_common.h" + +#include "draw_mode_engines.h" + +#include "ED_particle.h" + +#include "DEG_depsgraph_query.h" + +#include "draw_cache_impl.h" + +extern char datatoc_particle_strand_vert_glsl[]; +extern char datatoc_particle_strand_frag_glsl[]; + +/* *********** LISTS *********** */ + +typedef struct PARTICLE_PassList { + struct DRWPass *psys_edit_pass; +} PARTICLE_PassList; + +typedef struct PARTICLE_FramebufferList { + struct GPUFrameBuffer *fb; +} PARTICLE_FramebufferList; + +typedef struct PARTICLE_TextureList { + struct GPUTexture *texture; +} PARTICLE_TextureList; + +typedef struct PARTICLE_StorageList { + struct CustomStruct *block; + struct PARTICLE_PrivateData *g_data; +} PARTICLE_StorageList; + +typedef struct PARTICLE_Data { + void *engine_type; /* Required */ + PARTICLE_FramebufferList *fbl; + PARTICLE_TextureList *txl; + PARTICLE_PassList *psl; + PARTICLE_StorageList *stl; +} PARTICLE_Data; + +/* *********** STATIC *********** */ + +static struct { + struct GPUShader *strands_shader; + struct GPUShader *points_shader; +} e_data = {NULL}; /* Engine data */ + +typedef struct PARTICLE_PrivateData { + DRWShadingGroup *strands_group; + DRWShadingGroup *inner_points_group; + DRWShadingGroup *tip_points_group; +} PARTICLE_PrivateData; /* Transient data */ + +/* *********** FUNCTIONS *********** */ + +static void particle_engine_init(void *UNUSED(vedata)) +{ + if (!e_data.strands_shader) { + e_data.strands_shader = DRW_shader_create( + datatoc_particle_strand_vert_glsl, + NULL, + datatoc_particle_strand_frag_glsl, + ""); + } + if (!e_data.points_shader) { + e_data.points_shader = GPU_shader_get_builtin_shader( + GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR); + } +} + +static void particle_cache_init(void *vedata) +{ + PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl; + PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl; + + if (!stl->g_data) { + /* Alloc transient pointers */ + stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); + } + + /* Create a pass */ + psl->psys_edit_pass = DRW_pass_create("PSys Edit Pass", + (DRW_STATE_WRITE_COLOR | + DRW_STATE_WRITE_DEPTH | + DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_WIRE | + DRW_STATE_POINT)); + + stl->g_data->strands_group = DRW_shgroup_create( + e_data.strands_shader, psl->psys_edit_pass); + stl->g_data->inner_points_group = DRW_shgroup_create( + e_data.points_shader, psl->psys_edit_pass); + stl->g_data->tip_points_group = DRW_shgroup_create( + e_data.points_shader, psl->psys_edit_pass); + + static float size = 5.0f; + static float outline_width = 1.0f; + DRW_shgroup_uniform_float(stl->g_data->inner_points_group, "size", &size, 1); + DRW_shgroup_uniform_float(stl->g_data->inner_points_group, "outlineWidth", &outline_width, 1); + DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "size", &size, 1); + DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "outlineWidth", &outline_width, 1); +} + +static void particle_edit_cache_populate(void *vedata, + Object *object, + ParticleSystem *psys, + PTCacheEdit *edit) +{ + PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + ParticleEditSettings *pset = PE_settings(draw_ctx->scene); + { + struct Gwn_Batch *strands = + DRW_cache_particles_get_edit_strands(object, psys, edit); + DRW_shgroup_call_add(stl->g_data->strands_group, strands, NULL); + } + if (pset->selectmode == SCE_SELECT_POINT) { + struct Gwn_Batch *points = + DRW_cache_particles_get_edit_inner_points(object, psys, edit); + DRW_shgroup_call_add(stl->g_data->inner_points_group, points, NULL); + } + if (ELEM(pset->selectmode, SCE_SELECT_POINT, SCE_SELECT_END)) { + struct Gwn_Batch *points = + DRW_cache_particles_get_edit_tip_points(object, psys, edit); + DRW_shgroup_call_add(stl->g_data->tip_points_group, points, NULL); + } +} + +static void particle_cache_populate(void *vedata, Object *object) +{ + if (object->mode != OB_MODE_PARTICLE_EDIT) { + return; + } + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id); + /* Usually the edit structure is created by Particle Edit Mode Toggle + * operator, but sometimes it's invoked after tagging hair as outdated + * (for example, when toggling edit mode). That makes it impossible to + * create edit structure for until after next dependency graph evaluation. + * + * Ideally, the edit structure will be created here already via some + * dependency graph callback or so, but currently trying to make it nicer + * only causes bad level calls and breaks design from the past. + */ + Object *object_orig = DEG_get_original_object(object); + PTCacheEdit *edit = PE_create_current( + draw_ctx->depsgraph, scene_orig, object_orig); + if (edit == NULL) { + /* Happens when trying to edit particles in EMITTER mode without + * having them cached. + */ + return; + } + /* NOTE: We need to pass evaluated particle system, which we need + * to find first. + */ + ParticleSystem *psys = object->particlesystem.first; + ParticleSystem *psys_orig = object_orig->particlesystem.first; + while (psys_orig != NULL) { + if (PE_get_current_from_psys(psys_orig) == edit) { + break; + } + psys = psys->next; + psys_orig = psys_orig->next; + } + if (psys == NULL) { + printf("Error getting evaluated particle system for edit.\n"); + return; + } + particle_edit_cache_populate(vedata, object, psys, edit); +} + +/* Optional: Post-cache_populate callback */ +static void particle_cache_finish(void *UNUSED(vedata)) +{ +} + +/* Draw time ! Control rendering pipeline from here */ +static void particle_draw_scene(void *vedata) +{ + + PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl; + + DRW_draw_pass(psl->psys_edit_pass); +} + +static void particle_engine_free(void) +{ + DRW_SHADER_FREE_SAFE(e_data.strands_shader); +} + +static const DrawEngineDataSize particle_data_size = + DRW_VIEWPORT_DATA_SIZE(PARTICLE_Data); + +DrawEngineType draw_engine_particle_type = { + NULL, NULL, + N_("Particle Mode"), + &particle_data_size, + &particle_engine_init, + &particle_engine_free, + &particle_cache_init, + &particle_cache_populate, + &particle_cache_finish, + NULL, /* draw_background but not needed by mode engines */ + &particle_draw_scene, + NULL, + NULL, +}; |