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