doxygen: add newline after \file
[blender.git] / source / blender / draw / modes / particle_mode.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2016, Blender Foundation.
17  */
18
19 /** \file
20  * \ingroup draw
21  */
22
23 #include "DRW_render.h"
24
25 #include "DNA_object_types.h"
26 #include "DNA_particle_types.h"
27
28 #include "BKE_pointcache.h"
29
30 #include "GPU_shader.h"
31
32 #include "draw_common.h"
33
34 #include "ED_particle.h"
35
36 #include "DEG_depsgraph_query.h"
37
38 extern char datatoc_particle_strand_vert_glsl[];
39 extern char datatoc_particle_strand_frag_glsl[];
40 extern char datatoc_common_globals_lib_glsl[];
41
42 /* *********** LISTS *********** */
43
44 typedef struct PARTICLE_PassList {
45         struct DRWPass *psys_edit_pass;
46 } PARTICLE_PassList;
47
48 typedef struct PARTICLE_FramebufferList {
49         struct GPUFrameBuffer *fb;
50 } PARTICLE_FramebufferList;
51
52 typedef struct PARTICLE_TextureList {
53         struct GPUTexture *texture;
54 } PARTICLE_TextureList;
55
56 typedef struct PARTICLE_StorageList {
57         struct CustomStruct *block;
58         struct PARTICLE_PrivateData *g_data;
59 } PARTICLE_StorageList;
60
61 typedef struct PARTICLE_Data {
62         void *engine_type; /* Required */
63         PARTICLE_FramebufferList *fbl;
64         PARTICLE_TextureList *txl;
65         PARTICLE_PassList *psl;
66         PARTICLE_StorageList *stl;
67 } PARTICLE_Data;
68
69 /* *********** STATIC *********** */
70
71 static struct {
72         struct GPUShader *strands_shader;
73         struct GPUShader *strands_weight_shader;
74         struct GPUShader *points_shader;
75 } e_data = {NULL}; /* Engine data */
76
77 typedef struct PARTICLE_PrivateData {
78         DRWShadingGroup *strands_group;
79         DRWShadingGroup *inner_points_group;
80         DRWShadingGroup *tip_points_group;
81 } PARTICLE_PrivateData; /* Transient data */
82
83 /* *********** FUNCTIONS *********** */
84
85 static void particle_engine_init(void *UNUSED(vedata))
86 {
87         if (!e_data.strands_shader) {
88                 e_data.strands_shader = DRW_shader_create_with_lib(
89                         datatoc_particle_strand_vert_glsl,
90                         NULL,
91                         datatoc_particle_strand_frag_glsl,
92                         datatoc_common_globals_lib_glsl,
93                         "");
94
95                 e_data.strands_weight_shader = DRW_shader_create_with_lib(
96                         datatoc_particle_strand_vert_glsl,
97                         NULL,
98                         datatoc_particle_strand_frag_glsl,
99                         datatoc_common_globals_lib_glsl,
100                         "#define USE_WEIGHT");
101
102                 e_data.points_shader = DRW_shader_create_with_lib(
103                         datatoc_particle_strand_vert_glsl,
104                         NULL,
105                         datatoc_particle_strand_frag_glsl,
106                         datatoc_common_globals_lib_glsl,
107                         "#define USE_POINTS");
108         }
109 }
110
111 static void particle_cache_init(void *vedata)
112 {
113         PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
114         PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
115         const DRWContextState *draw_ctx = DRW_context_state_get();
116         ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
117         const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
118
119         if (!stl->g_data) {
120                 /* Alloc transient pointers */
121                 stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
122         }
123
124         /* Create a pass */
125         psl->psys_edit_pass = DRW_pass_create("PSys Edit Pass",
126                                               (DRW_STATE_WRITE_COLOR |
127                                                DRW_STATE_WRITE_DEPTH |
128                                                DRW_STATE_DEPTH_LESS_EQUAL |
129                                                DRW_STATE_WIRE |
130                                                DRW_STATE_POINT));
131
132         GPUShader *strand_shader = (use_weight) ? e_data.strands_weight_shader : e_data.strands_shader;
133         stl->g_data->strands_group = DRW_shgroup_create(strand_shader, psl->psys_edit_pass);
134         stl->g_data->inner_points_group = DRW_shgroup_create(e_data.points_shader, psl->psys_edit_pass);
135         stl->g_data->tip_points_group = DRW_shgroup_create(e_data.points_shader, psl->psys_edit_pass);
136
137         DRW_shgroup_uniform_block(stl->g_data->strands_group, "globalsBlock", G_draw.block_ubo);
138         DRW_shgroup_uniform_block(stl->g_data->inner_points_group, "globalsBlock", G_draw.block_ubo);
139         DRW_shgroup_uniform_block(stl->g_data->tip_points_group, "globalsBlock", G_draw.block_ubo);
140 }
141
142 static void particle_edit_cache_populate(void *vedata,
143                                          Object *object,
144                                          ParticleSystem *psys,
145                                          PTCacheEdit *edit)
146 {
147         PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
148         const DRWContextState *draw_ctx = DRW_context_state_get();
149         ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
150         const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
151         {
152                 struct GPUBatch *strands =
153                         DRW_cache_particles_get_edit_strands(object, psys, edit, use_weight);
154                 DRW_shgroup_call_add(stl->g_data->strands_group, strands, NULL);
155         }
156         if (pset->selectmode == SCE_SELECT_POINT) {
157                 struct GPUBatch *points =
158                         DRW_cache_particles_get_edit_inner_points(object, psys, edit);
159                 DRW_shgroup_call_add(stl->g_data->inner_points_group, points, NULL);
160         }
161         if (ELEM(pset->selectmode, SCE_SELECT_POINT, SCE_SELECT_END)) {
162                 struct GPUBatch *points =
163                         DRW_cache_particles_get_edit_tip_points(object, psys, edit);
164                 DRW_shgroup_call_add(stl->g_data->tip_points_group, points, NULL);
165         }
166 }
167
168 static void particle_cache_populate(void *vedata, Object *object)
169 {
170         if (object->mode != OB_MODE_PARTICLE_EDIT) {
171                 return;
172         }
173         const DRWContextState *draw_ctx = DRW_context_state_get();
174         Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
175         /* Usually the edit structure is created by Particle Edit Mode Toggle
176          * operator, but sometimes it's invoked after tagging hair as outdated
177          * (for example, when toggling edit mode). That makes it impossible to
178          * create edit structure for until after next dependency graph evaluation.
179          *
180          * Ideally, the edit structure will be created here already via some
181          * dependency graph callback or so, but currently trying to make it nicer
182          * only causes bad level calls and breaks design from the past.
183          */
184         Object *object_orig = DEG_get_original_object(object);
185         PTCacheEdit *edit = PE_create_current(
186                 draw_ctx->depsgraph, scene_orig, object_orig);
187         if (edit == NULL) {
188                 /* Happens when trying to edit particles in EMITTER mode without
189                  * having them cached.
190                  */
191                 return;
192         }
193         /* NOTE: We need to pass evaluated particle system, which we need
194          * to find first.
195          */
196         ParticleSystem *psys = object->particlesystem.first;
197         ParticleSystem *psys_orig = object_orig->particlesystem.first;
198         while (psys_orig != NULL) {
199                 if (PE_get_current_from_psys(psys_orig) == edit) {
200                         break;
201                 }
202                 psys = psys->next;
203                 psys_orig = psys_orig->next;
204         }
205         if (psys == NULL) {
206                 printf("Error getting evaluated particle system for edit.\n");
207                 return;
208         }
209         particle_edit_cache_populate(vedata, object, psys, edit);
210 }
211
212 /* Optional: Post-cache_populate callback */
213 static void particle_cache_finish(void *UNUSED(vedata))
214 {
215 }
216
217 /* Draw time ! Control rendering pipeline from here */
218 static void particle_draw_scene(void *vedata)
219 {
220
221         PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
222
223         DRW_draw_pass(psl->psys_edit_pass);
224 }
225
226 static void particle_engine_free(void)
227 {
228         DRW_SHADER_FREE_SAFE(e_data.strands_shader);
229         DRW_SHADER_FREE_SAFE(e_data.strands_weight_shader);
230         DRW_SHADER_FREE_SAFE(e_data.points_shader);
231 }
232
233 static const DrawEngineDataSize particle_data_size =
234       DRW_VIEWPORT_DATA_SIZE(PARTICLE_Data);
235
236 DrawEngineType draw_engine_particle_type = {
237         NULL, NULL,
238         N_("Particle Mode"),
239         &particle_data_size,
240         &particle_engine_init,
241         &particle_engine_free,
242         &particle_cache_init,
243         &particle_cache_populate,
244         &particle_cache_finish,
245         NULL, /* draw_background but not needed by mode engines */
246         &particle_draw_scene,
247         NULL,
248         NULL,
249 };