f659c33b5e14c528217883ad5553c7530a671236
[blender.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_particle_types.h"
33 #include "DNA_scene_types.h"
34
35 #include "BLI_listbase.h"
36 #include "BLI_utildefines.h"
37
38 #include "BKE_boids.h"
39 #include "BKE_context.h"
40 #include "BKE_depsgraph.h"
41 #include "BKE_main.h"
42 #include "BKE_particle.h"
43
44 #include "RNA_access.h"
45 #include "RNA_enum_types.h"
46 #include "RNA_define.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "physics_intern.h"
52
53 /************************ add/del boid rule operators *********************/
54 static int rule_add_exec(bContext *C, wmOperator *op)
55 {
56         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
57         ParticleSystem *psys= ptr.data;
58         Object *ob= ptr.id.data;
59         ParticleSettings *part;
60         int type= RNA_enum_get(op->ptr, "type");
61
62         BoidRule *rule;
63         BoidState *state;
64
65         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
66                 return OPERATOR_CANCELLED;
67
68         part = psys->part;
69
70         state = boid_get_current_state(part->boids);
71
72
73         for(rule=state->rules.first; rule; rule=rule->next)
74                 rule->flag &= ~BOIDRULE_CURRENT;
75
76         rule = boid_new_rule(type);
77         rule->flag |= BOIDRULE_CURRENT;
78
79         BLI_addtail(&state->rules, rule);
80
81         DAG_id_tag_update(&part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
82         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
83         
84         return OPERATOR_FINISHED;
85 }
86
87 void BOID_OT_rule_add(wmOperatorType *ot)
88 {
89         /* identifiers */
90         ot->name= "Add Boid Rule";
91         ot->description = "Add a boid rule to the current boid state";
92         ot->idname= "BOID_OT_rule_add";
93         
94         /* api callbacks */
95         ot->invoke= WM_menu_invoke;
96         ot->exec= rule_add_exec;
97         
98         /* flags */
99         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
100         
101         ot->prop= RNA_def_enum(ot->srna, "type", boidrule_type_items, 0, "Type", "");
102 }
103 static int rule_del_exec(bContext *C, wmOperator *UNUSED(op))
104 {
105         Main *bmain = CTX_data_main(C);
106         Scene *scene = CTX_data_scene(C);
107         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
108         ParticleSystem *psys= ptr.data;
109         Object *ob = ptr.id.data;
110         BoidRule *rule;
111         BoidState *state;
112
113         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
114                 return OPERATOR_CANCELLED;
115
116         state = boid_get_current_state(psys->part->boids);
117
118         
119         for(rule=state->rules.first; rule; rule=rule->next) {
120                 if(rule->flag & BOIDRULE_CURRENT) {
121                         BLI_remlink(&state->rules, rule);
122                         MEM_freeN(rule);
123                         break;
124                 }
125
126         }
127         rule = state->rules.first;
128
129         if(rule)
130                 rule->flag |= BOIDRULE_CURRENT;
131
132         DAG_scene_sort(bmain, scene);
133         DAG_id_tag_update(&psys->part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
134
135         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
136         
137         return OPERATOR_FINISHED;
138 }
139
140 void BOID_OT_rule_del(wmOperatorType *ot)
141 {
142         /* identifiers */
143         ot->name= "Remove Boid Rule";
144         ot->idname= "BOID_OT_rule_del";
145         
146         /* api callbacks */
147         ot->exec= rule_del_exec;
148
149         /* flags */
150         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
151 }
152
153 /************************ move up/down boid rule operators *********************/
154 static int rule_move_up_exec(bContext *C, wmOperator *UNUSED(op))
155 {
156         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
157         ParticleSystem *psys= ptr.data;
158         Object *ob = ptr.id.data;
159         BoidRule *rule;
160         BoidState *state;
161
162         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
163                 return OPERATOR_CANCELLED;
164         
165         state = boid_get_current_state(psys->part->boids);
166         for(rule = state->rules.first; rule; rule=rule->next) {
167                 if(rule->flag & BOIDRULE_CURRENT && rule->prev) {
168                         BLI_remlink(&state->rules, rule);
169                         BLI_insertlink(&state->rules, rule->prev->prev, rule);
170
171                         DAG_id_tag_update(&psys->part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
172                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
173                         break;
174                 }
175         }
176         
177         return OPERATOR_FINISHED;
178 }
179
180 void BOID_OT_rule_move_up(wmOperatorType *ot)
181 {
182         ot->name= "Move Up Boid Rule";
183         ot->description= "Move boid rule up in the list";
184         ot->idname= "BOID_OT_rule_move_up";
185
186         ot->exec= rule_move_up_exec;
187         
188         /* flags */
189         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
190 }
191
192 static int rule_move_down_exec(bContext *C, wmOperator *UNUSED(op))
193 {
194         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
195         ParticleSystem *psys= ptr.data;
196         Object *ob = ptr.id.data;
197         BoidRule *rule;
198         BoidState *state;
199
200         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
201                 return OPERATOR_CANCELLED;
202         
203         state = boid_get_current_state(psys->part->boids);
204         for(rule = state->rules.first; rule; rule=rule->next) {
205                 if(rule->flag & BOIDRULE_CURRENT && rule->next) {
206                         BLI_remlink(&state->rules, rule);
207                         BLI_insertlink(&state->rules, rule->next, rule);
208
209                         DAG_id_tag_update(&psys->part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
210                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
211                         break;
212                 }
213         }
214         
215         return OPERATOR_FINISHED;
216 }
217
218 void BOID_OT_rule_move_down(wmOperatorType *ot)
219 {
220         ot->name= "Move Down Boid Rule";
221         ot->description= "Move boid rule down in the list";
222         ot->idname= "BOID_OT_rule_move_down";
223
224         ot->exec= rule_move_down_exec;
225         
226         /* flags */
227         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
228 }
229
230
231 /************************ add/del boid state operators *********************/
232 static int state_add_exec(bContext *C, wmOperator *UNUSED(op))
233 {
234         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
235         ParticleSystem *psys= ptr.data;
236         Object *ob= ptr.id.data;
237         ParticleSettings *part;
238         BoidState *state;
239
240         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
241                 return OPERATOR_CANCELLED;
242
243         part = psys->part;
244
245         for(state=part->boids->states.first; state; state=state->next)
246                 state->flag &= ~BOIDSTATE_CURRENT;
247
248         state = boid_new_state(part->boids);
249         state->flag |= BOIDSTATE_CURRENT;
250
251         BLI_addtail(&part->boids->states, state);
252
253         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
254         
255         return OPERATOR_FINISHED;
256 }
257
258 void BOID_OT_state_add(wmOperatorType *ot)
259 {
260         /* identifiers */
261         ot->name= "Add Boid State";
262         ot->description = "Add a boid state to the particle system";
263         ot->idname= "BOID_OT_state_add";
264         
265         /* api callbacks */
266         ot->exec= state_add_exec;
267         
268         /* flags */
269         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
270 }
271 static int state_del_exec(bContext *C, wmOperator *UNUSED(op))
272 {
273         Main *bmain = CTX_data_main(C);
274         Scene *scene = CTX_data_scene(C);
275         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
276         ParticleSystem *psys= ptr.data;
277         Object *ob = ptr.id.data;
278         ParticleSettings *part;
279         BoidState *state;
280
281         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
282                 return OPERATOR_CANCELLED;
283
284         part = psys->part;
285         
286         for(state=part->boids->states.first; state; state=state->next) {
287                 if(state->flag & BOIDSTATE_CURRENT) {
288                         BLI_remlink(&part->boids->states, state);
289                         MEM_freeN(state);
290                         break;
291                 }
292
293         }
294
295         /* there must be at least one state */
296         if(!part->boids->states.first) {
297                 state = boid_new_state(part->boids);
298                 BLI_addtail(&part->boids->states, state);       
299         }
300         else
301                 state = part->boids->states.first;
302
303         state->flag |= BOIDSTATE_CURRENT;
304
305         DAG_scene_sort(bmain, scene);
306         DAG_id_tag_update(&psys->part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
307
308         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
309         
310         return OPERATOR_FINISHED;
311 }
312
313 void BOID_OT_state_del(wmOperatorType *ot)
314 {
315         /* identifiers */
316         ot->name= "Remove Boid State";
317         ot->idname= "BOID_OT_state_del";
318         
319         /* api callbacks */
320         ot->exec= state_del_exec;
321
322         /* flags */
323         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
324 }
325
326 /************************ move up/down boid state operators *********************/
327 static int state_move_up_exec(bContext *C, wmOperator *UNUSED(op))
328 {
329         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
330         ParticleSystem *psys= ptr.data;
331         Object *ob = ptr.id.data;
332         BoidSettings *boids;
333         BoidState *state;
334
335         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
336                 return OPERATOR_CANCELLED;
337
338         boids = psys->part->boids;
339         
340         for(state = boids->states.first; state; state=state->next) {
341                 if(state->flag & BOIDSTATE_CURRENT && state->prev) {
342                         BLI_remlink(&boids->states, state);
343                         BLI_insertlink(&boids->states, state->prev->prev, state);
344                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
345                         break;
346                 }
347         }
348         
349         return OPERATOR_FINISHED;
350 }
351
352 void BOID_OT_state_move_up(wmOperatorType *ot)
353 {
354         ot->name= "Move Up Boid State";
355         ot->description= "Move boid state up in the list";
356         ot->idname= "BOID_OT_state_move_up";
357
358         ot->exec= state_move_up_exec;
359         
360         /* flags */
361         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
362 }
363
364 static int state_move_down_exec(bContext *C, wmOperator *UNUSED(op))
365 {
366         PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
367         ParticleSystem *psys= ptr.data;
368         BoidSettings *boids;
369         BoidState *state;
370
371         if(!psys || !psys->part || psys->part->phystype != PART_PHYS_BOIDS)
372                 return OPERATOR_CANCELLED;
373
374         boids = psys->part->boids;
375         
376         for(state = boids->states.first; state; state=state->next) {
377                 if(state->flag & BOIDSTATE_CURRENT && state->next) {
378                         BLI_remlink(&boids->states, state);
379                         BLI_insertlink(&boids->states, state->next, state);
380                         DAG_id_tag_update(&psys->part->id, OB_RECALC_DATA|PSYS_RECALC_RESET);
381                         break;
382                 }
383         }
384         
385         return OPERATOR_FINISHED;
386 }
387
388 void BOID_OT_state_move_down(wmOperatorType *ot)
389 {
390         ot->name= "Move Down Boid State";
391         ot->description= "Move boid state down in the list";
392         ot->idname= "BOID_OT_state_move_down";
393
394         ot->exec= state_move_down_exec;
395         
396         /* flags */
397         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
398 }
399