Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / physics / particle_boids.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Janne Karhu.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/physics/particle_boids.c
27  *  \ingroup edphys
28  */
29
30
31 #include <stdlib.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_particle_types.h"
36
37 #include "BLI_listbase.h"
38 #include "BLI_utildefines.h"
39
40 #include "BKE_boids.h"
41 #include "BKE_context.h"
42 #include "BKE_main.h"
43 #include "BKE_particle.h"
44
45 #include "DEG_depsgraph.h"
46 #include "DEG_depsgraph_build.h"
47
48 #include "RNA_access.h"
49 #include "RNA_enum_types.h"
50 #include "RNA_define.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "physics_intern.h"
56
57 /************************ add/del boid rule operators *********************/
58 static int rule_add_exec(bContext *C, wmOperator *op)
59 {
60         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
61         ParticleSettings *part = ptr.data;
62         int type= RNA_enum_get(op->ptr, "type");
63
64         BoidRule *rule;
65         BoidState *state;
66
67         if (!part || part->phystype != PART_PHYS_BOIDS)
68                 return OPERATOR_CANCELLED;
69
70         state = boid_get_current_state(part->boids);
71
72         for (rule=state->rules.first; rule; rule=rule->next)
73                 rule->flag &= ~BOIDRULE_CURRENT;
74
75         rule = boid_new_rule(type);
76         rule->flag |= BOIDRULE_CURRENT;
77
78         BLI_addtail(&state->rules, rule);
79
80         DEG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
81         
82         return OPERATOR_FINISHED;
83 }
84
85 void BOID_OT_rule_add(wmOperatorType *ot)
86 {
87         /* identifiers */
88         ot->name = "Add Boid Rule";
89         ot->description = "Add a boid rule to the current boid state";
90         ot->idname = "BOID_OT_rule_add";
91         
92         /* api callbacks */
93         ot->invoke = WM_menu_invoke;
94         ot->exec = rule_add_exec;
95         
96         /* flags */
97         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
98         
99         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_boidrule_type_items, 0, "Type", "");
100 }
101 static int rule_del_exec(bContext *C, wmOperator *UNUSED(op))
102 {
103         Main *bmain = CTX_data_main(C);
104         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
105         ParticleSettings *part = ptr.data;
106         BoidRule *rule;
107         BoidState *state;
108
109         if (!part || part->phystype != PART_PHYS_BOIDS)
110                 return OPERATOR_CANCELLED;
111
112         state = boid_get_current_state(part->boids);
113
114         for (rule=state->rules.first; rule; rule=rule->next) {
115                 if (rule->flag & BOIDRULE_CURRENT) {
116                         BLI_remlink(&state->rules, rule);
117                         MEM_freeN(rule);
118                         break;
119                 }
120         }
121         rule = state->rules.first;
122
123         if (rule)
124                 rule->flag |= BOIDRULE_CURRENT;
125
126         DEG_relations_tag_update(bmain);
127         DEG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
128
129         return OPERATOR_FINISHED;
130 }
131
132 void BOID_OT_rule_del(wmOperatorType *ot)
133 {
134         /* identifiers */
135         ot->name = "Remove Boid Rule";
136         ot->idname = "BOID_OT_rule_del";
137         ot->description = "Delete current boid rule";
138         
139         /* api callbacks */
140         ot->exec = rule_del_exec;
141
142         /* flags */
143         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
144 }
145
146 /************************ move up/down boid rule operators *********************/
147 static int rule_move_up_exec(bContext *C, wmOperator *UNUSED(op))
148 {
149         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
150         ParticleSettings *part = ptr.data;
151         BoidRule *rule;
152         BoidState *state;
153
154         if (!part || part->phystype != PART_PHYS_BOIDS)
155                 return OPERATOR_CANCELLED;
156         
157         state = boid_get_current_state(part->boids);
158         for (rule = state->rules.first; rule; rule=rule->next) {
159                 if (rule->flag & BOIDRULE_CURRENT && rule->prev) {
160                         BLI_remlink(&state->rules, rule);
161                         BLI_insertlinkbefore(&state->rules, rule->prev, rule);
162
163                         DEG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
164                         break;
165                 }
166         }
167         
168         return OPERATOR_FINISHED;
169 }
170
171 void BOID_OT_rule_move_up(wmOperatorType *ot)
172 {
173         ot->name = "Move Up Boid Rule";
174         ot->description = "Move boid rule up in the list";
175         ot->idname = "BOID_OT_rule_move_up";
176
177         ot->exec = rule_move_up_exec;
178         
179         /* flags */
180         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
181 }
182
183 static int rule_move_down_exec(bContext *C, wmOperator *UNUSED(op))
184 {
185         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
186         ParticleSettings *part = ptr.data;
187         BoidRule *rule;
188         BoidState *state;
189
190         if (!part || part->phystype != PART_PHYS_BOIDS)
191                 return OPERATOR_CANCELLED;
192         
193         state = boid_get_current_state(part->boids);
194         for (rule = state->rules.first; rule; rule=rule->next) {
195                 if (rule->flag & BOIDRULE_CURRENT && rule->next) {
196                         BLI_remlink(&state->rules, rule);
197                         BLI_insertlinkafter(&state->rules, rule->next, rule);
198
199                         DEG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
200                         break;
201                 }
202         }
203         
204         return OPERATOR_FINISHED;
205 }
206
207 void BOID_OT_rule_move_down(wmOperatorType *ot)
208 {
209         ot->name = "Move Down Boid Rule";
210         ot->description = "Move boid rule down in the list";
211         ot->idname = "BOID_OT_rule_move_down";
212
213         ot->exec = rule_move_down_exec;
214         
215         /* flags */
216         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
217 }
218
219
220 /************************ add/del boid state operators *********************/
221 static int state_add_exec(bContext *C, wmOperator *UNUSED(op))
222 {
223         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
224         ParticleSettings *part = ptr.data;
225         BoidState *state;
226
227         if (!part || part->phystype != PART_PHYS_BOIDS)
228                 return OPERATOR_CANCELLED;
229
230         for (state=part->boids->states.first; state; state=state->next)
231                 state->flag &= ~BOIDSTATE_CURRENT;
232
233         state = boid_new_state(part->boids);
234         state->flag |= BOIDSTATE_CURRENT;
235
236         BLI_addtail(&part->boids->states, state);
237
238         return OPERATOR_FINISHED;
239 }
240
241 void BOID_OT_state_add(wmOperatorType *ot)
242 {
243         /* identifiers */
244         ot->name = "Add Boid State";
245         ot->description = "Add a boid state to the particle system";
246         ot->idname = "BOID_OT_state_add";
247         
248         /* api callbacks */
249         ot->exec = state_add_exec;
250         
251         /* flags */
252         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
253 }
254 static int state_del_exec(bContext *C, wmOperator *UNUSED(op))
255 {
256         Main *bmain = CTX_data_main(C);
257         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
258         ParticleSettings *part = ptr.data;
259         BoidState *state;
260
261         if (!part || part->phystype != PART_PHYS_BOIDS)
262                 return OPERATOR_CANCELLED;
263
264         for (state=part->boids->states.first; state; state=state->next) {
265                 if (state->flag & BOIDSTATE_CURRENT) {
266                         BLI_remlink(&part->boids->states, state);
267                         MEM_freeN(state);
268                         break;
269                 }
270         }
271
272         /* there must be at least one state */
273         if (!part->boids->states.first) {
274                 state = boid_new_state(part->boids);
275                 BLI_addtail(&part->boids->states, state);
276         }
277         else
278                 state = part->boids->states.first;
279
280         state->flag |= BOIDSTATE_CURRENT;
281
282         DEG_relations_tag_update(bmain);
283         DEG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
284         
285         return OPERATOR_FINISHED;
286 }
287
288 void BOID_OT_state_del(wmOperatorType *ot)
289 {
290         /* identifiers */
291         ot->name = "Remove Boid State";
292         ot->idname = "BOID_OT_state_del";
293         ot->description = "Delete current boid state";
294         
295         /* api callbacks */
296         ot->exec = state_del_exec;
297
298         /* flags */
299         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
300 }
301
302 /************************ move up/down boid state operators *********************/
303 static int state_move_up_exec(bContext *C, wmOperator *UNUSED(op))
304 {
305         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
306         ParticleSettings *part = ptr.data;
307         BoidSettings *boids;
308         BoidState *state;
309
310         if (!part || part->phystype != PART_PHYS_BOIDS)
311                 return OPERATOR_CANCELLED;
312
313         boids = part->boids;
314         
315         for (state = boids->states.first; state; state=state->next) {
316                 if (state->flag & BOIDSTATE_CURRENT && state->prev) {
317                         BLI_remlink(&boids->states, state);
318                         BLI_insertlinkbefore(&boids->states, state->prev, state);
319                         break;
320                 }
321         }
322         
323         return OPERATOR_FINISHED;
324 }
325
326 void BOID_OT_state_move_up(wmOperatorType *ot)
327 {
328         ot->name = "Move Up Boid State";
329         ot->description = "Move boid state up in the list";
330         ot->idname = "BOID_OT_state_move_up";
331
332         ot->exec = state_move_up_exec;
333         
334         /* flags */
335         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
336 }
337
338 static int state_move_down_exec(bContext *C, wmOperator *UNUSED(op))
339 {
340         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_settings", &RNA_ParticleSettings);
341         ParticleSettings *part = ptr.data;
342         BoidSettings *boids;
343         BoidState *state;
344
345         if (!part || part->phystype != PART_PHYS_BOIDS)
346                 return OPERATOR_CANCELLED;
347
348         boids = part->boids;
349         
350         for (state = boids->states.first; state; state=state->next) {
351                 if (state->flag & BOIDSTATE_CURRENT && state->next) {
352                         BLI_remlink(&boids->states, state);
353                         BLI_insertlinkafter(&boids->states, state->next, state);
354                         DEG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
355                         break;
356                 }
357         }
358         
359         return OPERATOR_FINISHED;
360 }
361
362 void BOID_OT_state_move_down(wmOperatorType *ot)
363 {
364         ot->name = "Move Down Boid State";
365         ot->description = "Move boid state down in the list";
366         ot->idname = "BOID_OT_state_move_down";
367
368         ot->exec = state_move_down_exec;
369         
370         /* flags */
371         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
372 }
373